编译器合成的拷贝构造函数
定义:
只有一个参数,的引用(经常使用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时刻。