概述
使用 class object 时,在以下三种情况会以一个 object 的内容作为另一个 class object 的初值,即用到拷贝构造函数:
- 定义一个 class object 并对其进行初始化;
- class object 作为一个参数传递给函数;
- class object 作为函数的返回值;
若用户没有显示声明或定义拷贝构造函数,则 C++ 在 必要 时为 class 声明或定义隐式拷贝构造函数,若出现以下的情况时,该拷贝构造函数是 trivial 的:
- their class has no virtual functions and no virtual base class(es).
- all direct base classes and non-static data members of their class have trivial constructors.
- Otherwise, the copy constructor are non-trivial. Implicitly-declared non-trivial copy constructor.
默认拷贝构造函数
在以下四种情况下,编译器会合成一个 non-trivial 的默认拷贝构造函数:
- 当 class 内含一个具有 copy constructor 的 member object;
- 当 class 继承自一个具有 copy constructor 的 base class;
- 当 class 声明有 virtual functions;
- 当 class 派生自 virtual base class(es);
前面两种情况,编译器必须将 member 或 base class 的 copy constructor 放置在默认拷贝构造函数中,以下例子同时满足这两个情况:
#include <iostream>
using namespace std;
class Foo {
public:
Foo() {}
Foo(const Foo &foo) { cout << "Foo‘s copy construct!" << endl; }
};
class Word: public Foo {
public:
int x;
Foo foo;
};
int main()
{
Word ba;
Word bb = ba;
return 0;
}
执行结果:编译器在合成的拷贝构造函数中调用了两次 Foo 类的拷贝构造函数;
(gdb) r
Starting program: ./test02
Breakpoint 1, main () at test02.cpp:20
20 Word ba;
(gdb) s
Word::Word (this=0xbffff020) at test02.cpp:11
11 class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff020) at test02.cpp:7
7 Foo() {}
(gdb) s
Foo::Foo (this=0xbffff024) at test02.cpp:7
7 Foo() {}
(gdb) s
main () at test02.cpp:21
21 Word bb = ba;
(gdb) s
Word::Word (this=0xbffff028) at test02.cpp:11
11 class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff028, foo=...) at test02.cpp:8
8 Foo(const Foo &foo) { cout << "Foo‘s copy construct!" << endl; }
(gdb) s
Foo‘s copy construct!
Foo::Foo (this=0xbffff02c, foo=...) at test02.cpp:8
8 Foo(const Foo &foo) { cout << "Foo‘s copy construct!" << endl; }
(gdb) s
Foo‘s copy construct!
main () at test02.cpp:22
22 return 0;
(gdb) s
23 }
(gdb)
第三种情况,若是相同 class 的 object 直接的初始化,可以采用 bitwise copy 方式进行,因为 vptr 指向相同的虚函数表;若是使用派生类 object 初始化 基类 object 时,则编译器会重新设定 class object 的 virtual table 的指针,因为不同类的 vptr 指向各自的虚函数表;
#include <iostream>
using namespace std;
class Foo {
public:
virtual void func()
{ cout << "virtual function in Foo!" << endl; }
};
class Word: public Foo {
public:
void func()
{ cout << "virtual function in Word!" << endl; }
};
int main()
{
Word b1;
Word b2 = b1; // 相同类对象之间初始化,vptr直接复制,指向相同的virtual function table
b2.func();
Foo foo = b1; // 不同类对象之间初始化,发生切割,vptr不直接复制,指向不同的virtual function table
foo.func();
return 0;
}
执行结果:
(gdb) b 19
Breakpoint 1 at 0x8048809: file test03.cpp, line 19.
(gdb) r
Starting program: /home/nifengweijifen/linuxStudy/ObjectModel/chap02/test03
Breakpoint 1, main () at test03.cpp:19
19 Word b1;
(gdb) s
Word::Word (this=0xbffff024) at test03.cpp:12
12 class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff024) at test03.cpp:6
6 class Foo {
(gdb) s
main () at test03.cpp:20
20 Word b2 = b1; //相同类之间的初始化,直接复制 vptr,指向相同的virtual function table
(gdb) s
Word::Word (this=0xbffff028) at test03.cpp:12
12 class Word: public Foo {
(gdb) s
Foo::Foo (this=0xbffff028) at test03.cpp:6
6 class Foo {
(gdb) s
main () at test03.cpp:21
21 b2.func();
(gdb) s
Word::func (this=0xbffff028) at test03.cpp:15
15 { cout << "virtual function in Bar!" << endl; }
(gdb) s
virtual function in Word!
main () at test03.cpp:23
23 Foo foo = b1; // 不同类之间的初始化,发生切割,vptr不直接复制,指向不同的virtual function table
(gdb) s
Foo::Foo (this=0xbffff02c) at test03.cpp:6
6 class Foo {
(gdb) s
main () at test03.cpp:24
24 foo.func();
(gdb) s
Foo::func (this=0xbffff02c) at test03.cpp:9
9 { cout << "virtual function in Foo!" << endl; }
(gdb) s
virtual function in Foo!
main () at test03.cpp:25
25 return 0;
(gdb) s
26 }
(gdb)
第四种情况和第三种情况相似,若是相同 class 的 object 直接的初始化,可以采用 bitwise copy 方式进行;若是使用派生类 object 初始化 基类 object 时,则编译器会重新设定 virtual base class 的指针;
时间: 2024-12-09 17:44:29