首页 > 代码库 > 编译器合成复制构造函数
编译器合成复制构造函数
定义:
只有单个形参,该形参是对本类类型对象的引用(常用const修饰),这样的构造函数成为复制构造函数。
使用方式:
(1)显示使用----用一个同类型的对象初始化该对象时;
(2)隐式使用----将该类型的对象传递给函数或从函数返回该类型对象时。
三种类型的复制构造函数:
*bitwise copy constructor :逐位复制-----默认方式
*合成的 copy constructor :编译器合成----执行逐个成员初始化(memberwise initialize),只完成必要的工作,
*自定义的copy constructor:由类设计者定义------因为有些类必须对复制对象加以控制,如数据成员是指针的情况或者数据成员表示在构造函数中分配的其他资源,或类在创建新对象时必须要做一些特定工作,这时候就需要定义自己的复制构造函数。
关于浅拷贝与深拷贝:
浅拷贝:shllow copy= bitwise copy-----逐位(字节)拷贝(默认情况)
例子:
- <span style="font-size:24px;">class Base{
- public:
- int a;
- char ch;
- char* str;
- }
- Base b1;
- b1.a=15;
- b1.ch=‘c‘;
- b1.str="string";
- b2=b2;</span>
现在看看b1和b2的内存布局(不考虑对齐):
可以看到:b1.str和b2.str指向了同一内存空间,即当一方撤销时,另一方将受到影响,故应极力避免这种情况-----深度拷贝
深度拷贝:deep copy = memberwise copy-----挨个成员拷贝
再看b1和b2的内存布局:
此时b1.str和b2.str指向了不同的内存空间,但内容(string)还是一样的。
由于编译器默认是bitwise copy semantics
即如果类中没有明确定义或被编译器合成copy constructor(即memberwise copy),则默认使用bitwise copy形式。
注:以上编译器合成copy constructor和bitwise copy constructor两种情况,均不需要类设计的参与!
那么什么 情况下bitwise copy semantics会失效呢?
有四种情况:
(1)当class内含一个class member object ,而后者的class声明有一个copy constructor 时----被class设计者明确声明或被编译器合成-------递归调用;
(2)当class继承自一个base class,而后者存在一个copy constructor时-----被class设计者明确声明或被编译器合成-------递归调用;
(3)当class声明了一个或多个virtual functions时-------因为此时要考虑类对象中的虚函数表指针vptr的值。
当在同层对象之间进行初始化时,bitwise copy已经够用了(为简化,此时不考虑含有指针成员的情况);
例子:
- <span style="font-size:18px;">class ZooAnimal{
- public:
- ZooAnimal();
- virtual ~ZooAnimal();
- virtual void animate();
- virtual void draw();
- .....
- };
- class Bear : public ZooAnimal{
- public:
- Bear();
- void animate();
- void draw();
- virtual void dance();
- ......
- };
- Bear yogi;
- Bear winnie = yogi; //bitwise copy</span>
其内存布局如下:
但是如果存在:当一个base class object以其derived class 的object内容做初始化操作时,此时若bitwise copy显然会出错,因为其vptr将指向不同的虚表,故此时编译器需要合成copy constrctor,以保证vptr复制操作的安全。合成出来的base class object copy constructor会明确是定object的vptr指向base class object 的vitrual table,而不是直接从右手边的class object 中将其vptr现值拷贝过来。
如:
- <span style="font-size:18px;">void draw(const ZooAnimal& zoey )
- {
- zoey.draw();
- }
- ZooAnimal franny = yogi;//发生切割(sliced)行为
- draw(yogi); //调用Bear::draw();
- draw(franny); //调用ZooAnimal::draw()</span><span style="font-size:16px;">
- </span>
其内存布局如下(此时由编译器合成copy constructor):
(4)当class派生自一个继承串链时,其中有一个或多个virtual base classes时。
编译器合成复制构造函数