Copy Constructor的构造操作

Copy Constructor的构造操作

       有三种情况,会以一个object的内容作为另一个class object的初值:

1、  对一个object做显式的初始化操作

class X{…};

X a;

X b = a;

       2、当object被当做参数交给某个函数:

          X a;

          void foo(X x);

          foo(a);

3、  当返回值为object:

X foo

{

        X a;

        return a;

}

       假设class X显式定义了一个copy constructor,类似下面这样:

       X::X(const X& x);

       则在大部分情况下,当一个class object以另一个同类实例作为初值,上述的copy constructor就会被调用。

       那如果class没有提供一个explicit copy constructor的话,编译器是如何处理的呢?这时就要所谓的default memberwise initialization起作用了。default memberwise initialization也就是把object内每一个内建的或派生的data member的值,拷贝到另一个object,对于member class object,则以递归的方式继续实施memberwise initialization。从对象的数据成员角度出发,具体到对象的每一个数据成员的操作,编译器通常采用(可以认为就是)bitwise copy(按位拷贝)操作,就像memcpy或者memset函数一样,原样将内存中的数据按位复制一份。但是并不是所有不提供explicit copy constructor的class都会展现bitwise copy。

       像default constructor,C++ Standard把copy constructor区分为trivial和nontrivial两种。其中nontrivial copy constructor才会被编译器真正合成与程序之中,而trivial copy constructor实际上被没有被真正合成。决定copy constructor是否为trivial的标准对应的class是否展现出bitwise copy。

       那什么情况下,copy constructor是nontrivial,或者说class不展现bitwise copy呢?分为以下4中情况:

第一、当class内含有一个member object,而后者的class有一个copy constructor(无论是显式声明,还是编译器隐式合成)。

       因为编译器必须将member object的“copy constructor的调用操作”安插到被编译器合成的copy constructor中,否则无法调用member object的copy constructor。

第二、当class继承自一个base class,而后者存在一个copy constructor(无论是显式声明,还是编译器隐式合成)。

       因为编译器必须将base class的“copy constructor的调用操作”安插到被编译器合成的copy constructor中,否则无法调用base class的copy constructor。

第三、当class声明了至少一个virtual function

       当class至少有一个virtual function时,这个class的object必然会有virtual table和virtual point。所以对于每一个新产生的class object的virtual point,必须正确设定初值。如果采用bitwise copy,在一般情况下是可以满足要求的。但是当一个base class object以其derived class的object内容做初始化时,如果采用bitwise copy的话,virtual point就难以保证安全,因为从derived class object拷贝过来的virtual point指向的还是derived class的virtual table,而并不是base class的virtual table。

第四、当class直接或间接地继承了至少一个virtual base class

       每一个编译器对于虚拟继承的支持承诺,都代表必须让derived class object中的virtual base class subobject位置在执行期就准备妥当。但bitwise copy 可能会破坏这个位置,所以编译器在这种情况不会采用bitwise copy。

总结,以上4种情况下class不再保持bitwise copy,而且explicit copy constructor未被声明,编译器为了正确处理“以一个class object作为另一个class object的初值”,会为class合成nontrivial copy constructor。

 

原文地址:https://www.cnblogs.com/wuhaowinner/p/copy_constructor.html