- class X { ... };
- X x;
- X xx = x; // 情况1,赋值对象
- extern void foo( X x);
- void bar()
- {
- X xx;
- foo( xx ); // 情况2,作为参数
- }
- X foo_bar()
- {
- X xx;
- return xx; // 情况3,作为返回值
- }
Default Memberwise Initalization
如果class 没有提供一个explicit copy constructor又当如何?当class object 以 “相同class的另一个object”作为初值时,其内是以所谓的default memberwise initalization手法完成的,也就是把每一个内建的或派生的data member的值,从某个object拷贝一份到另一个object身上。不过它不会拷贝其中的member class object, 而是以递归的方式实行memberwise initalization.
例子:
- class String
- {
- public:
- //..没有explicit copy constructor
- private:
- char *str;
- int len;
- };
- class Word
- {
- public:
- //..没有explicit copy constructor
- private:
- int _occurs;
- String _word; //String object成为class word的一个member. 此处以递归的方式实行memberwise initalization.
- // Word 是否合成 copy constructor 取决于 bitwise copy semantics.
- //此例子不合成copy constructor 编译器会自动复制每一个数据成员
- };
指出一个错误概念:“如果一个class未定义copy constructor,编译器就自动为它产生出一个”这句话不对
正确的概念:Default constructor 和 copy constructor在必要的时候才由编译器产生出来。“必要”意指当class不展现bitwise copy semantics时。
Bitwise Copy Semantics(位逐次拷贝)
上例展示了Bitwise copy Semantics.
有一点很值得注意:在被合成出来的copy constructor中,如整数、指针、数组等等的nonclass memebers也都会被复制,正如我们所期待的一样。
不要Bitwise Copy Semantics
有四种情况不展示Bitwise Copy Semantics, 不展示的时候需要编译器合成copy constructor:
(1)当class内含一个member object而后者的class声明有一个copy constructor时
(2)当class继承自一个base class 而后者存在有一个copy constructor时
(3)当class声明了一个或多个virtual functions时
(4)当class派生自一个继承串链,其中有一个或多个virtual base classes时
结论:如果是自定义复制构造函数时,需要自己把每一个数据成员复制;如果是没有自定义复制构造函数,无论是合成或非合成,编译器都会自动复制每一个数据成员。复制构造函数的用途是:如果构造函数中存在动态内存分配,则必须定义复制构造函数,否则会出现“指针悬挂问题”。
- class A
- {
- private:
- int *p;
- public:
- A()
- {
- p = new int(3);
- }
- };
在这种情况下,复制对象,会造成两个对象的成员指向同一地址。
重新设定Virtual Table的指针
例子:
- class ZooAninal
- {
- 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;
把yogi 的vptr值拷贝给winnie的vptr是安全的
ZooAnimal franny = yogi; // 这会发生 切割行为
合成出来的ZooAinmal copy constructor会明确设定object的vptr指向ZooAnimal class的virtual table,而 不是直接从右手边的class object中将其vptr现值拷贝过来。
处理Virtual Base Class Subobject
总结:
可以这么认为,并不是在没有自定义copy constructor的时候编译器就合成一个copy constructor,而是在没有bitwise copy semantics时会合成一个 ,在执行default memberwise initialization的时候。
并没有把这个操作当做在copy constructor的时候执行,这个操作并不认为是在copy constructor的时候完成的。这是我对这本书这一节的理解。