一 Copy Constructor的定义:
拷贝构造函数的第一个参数与调用的class object 类型相同,可以有多个形参,但是后面的参数都需要提供默认值。
例如:
X::X(const X& x);
Y::Y(const Y&y,int temp=0);
在大部分情况下,当一个class object以另一个同类实体作为初值时,上述的constructor会被调用。
二 Copy Constructor的三种调用情况:
有三种情况会自动调用Copy Constructor,以一个object的内容作为另外一个class object 的初值。分别是:
1.当对一个object做明确的初始化操作,例如
class X{...}; X x; X xx=x;//明确地以一个object的内容为另一个class object的初值
2.当object被当做参数交给某个函数时,例如:
extern void foo(X X); void bar() { X xx; foo(xx);//以xx作为foo()第一个参数的初值 }
3.当函数传回一个class object时,例如:
X foo_bar(){
X xx;
return xx;
}
二 Copy Constructor 的合成
1.Bitwise Copy Semantics
当我们定义一个类如下所示:
class Word{ public: Word(const char *); ~Word(){delete [] str;} private : int cnt; char *str; }此时,
情况一: Word noun("book"); void foo() { Word verb=noun; } 情况二: Word noun("book"); void foo(Word tempword){//foo定义,此时会产生一个Word类型的临时变量,在临时变量被销毁的时候,str指向的空间也会被释放掉 } foo(noun);//foo调用
此时,虽然Word没有定义copy constructor,但是编译器也不会合成一个。此时编译器使用Bitwise Copy Semantics(按位拷贝语义)直接将noun对象空间中的类容拷贝到verb对象空间。使用Bitwise Copy Semantics后的对象空间布局如下图所示:
注意在verb对象消亡的时候,str指向的空间也被释放掉了,当noun对象再去访问的时候,str已经是一个野指针,访问不合法,这一点在写程序的时候一定要注意,想当初,我调这个bug调了不知道多久。
2. 不要Bitwise Copy Semantics
什么时候一个class不展现出"bitewise copy semantics" 呢?有四种情况:
1.当class内含一个member object 而后者的class声明有一个copy constructor时(不论是被class 设计者明确地声明,或者是被编译器合成)。
2.当class继承自一个base class 而后者存在有一个copy constructor时(再次强调,不论是被明确声明或者是被合成而得)。
3.当class声明了一个或者多个virtual functions 时。
4.当class 派生自一个继承串链,其中有一个或多个virtual base classes时。
前两种情况,编译器必须将member或者base class的"copy constructor调用操作"安插到被合成的copy constructor中,