《inside the c++ object model》读书笔记 之二:构造函数

构造函数

2.1 default constructor的构建操作:
...default constructor会在,当编译器需要它的时候,被合成出来例如:对于class X,如果没有任何user-declared constructor,那么会有一个default constructor被暗中(implicitly)声明出来,...一个被暗中声明出来的default constructor 可能是一个trivial(没啥用的)constructor,nontrivial constructor就是编译器需要的那一种.

...对于nontrival default constructor有下列四种情况:
  1)带有default constructor的member class object:
  如果一个class含有一个member class object,并且这个object有一个default constructor,那么这个class的implicit default constructor就是nontrivial,编译器会为其合成一个default constructor,不过这个合成操作只有在constructor真正需要被调用时才会发生.
  如果class A内含有一个或一个以上member class objects ,那么class A的每一个constructor必须调用每一个member classes的default constructor,其调用顺序将按照"member objects"在class中的声明次序来执行,并且编译器扩张的码将安插在user code 执行之前.
  2)带有default constructor的base class:
  如果一个没有任何constructor的class派生自一个"带有default constructor"的base class,那么这个derived class的default constructor将视为nonrtivial,它会被合成出来.它将按照base class的声明次序来一次调用每一个base class的default constructor.
  如果设计者提供多个constructors,但其中都没有default constructor,编译器会扩张现有的每一个constructors,将"用以调用所有必要的default constructors"的程序代码加进去,它不会合成一个新的default constructor,如果同时亦存在着"带有default constructor"的member class objects,那么,那些default constructor也会被调用(在所有base class constructor 都被调用之后).
  3)带有一个virtual function的class:
  另有两种情况,也需要合成出default constructor:
    a)class声明(或继承)一个virtual function.
    b)class派生自一个继承串连,其中有一个或更多的virtual base classes.
  以下两个扩张会在编译期间发生:
    a)一个virtual function table(vtbl)会被编译器产生出来,内放class的virtual function地址.
    b)在每一个class object中,一个额外的pointer member(vptr)会被编译器合成出来,内含相关的class vtbl的地址.
注:对于那些未声明任何constructor的classes,编译器会为它们合成一个default constructor,以便正确地初始化每一个class object的vptr.
  4)带有一个virtual base class的class:
  对于class所定义的每一个constructor,编译器会安插那些"允许每一个virtual base class的执行期存取操作"的码.如果没有声明任何constructor,编译器必须为它合成出一个default constructor.
  总结:以上四种 情况编译器必须为未声明constructor之classes合成一个default constructor,这些合成物成为implicit nontrivial default constructor,在合成的default constructor中,只有base class subobjects和member class objects会被初始化,所以其他的nonstatic data members,都不会被初始化.


2.2copy constructor的构建操作:
...有三种情况,会以一个object的内容作为另一个class object的初值:
  1)对一个object做明确的初始化操作.
  2)当object被当做参数交给某个函数时.
  3)当函数传回一个class object时.

...如果一个class没有提供一个explicit copy constructor,则当class object以"相同class的另一个object"作为初值时,其内部是以所谓default memberwise initialization手法完成,也就是说把一个,内建的或派生的data member(如一个指针或是数组)的值拷贝一份到另一个object身上,不过她不会拷贝其中的member class obect,而是以递归的方式施行memberwise initialization.

...copy constructor在必要的时候由编译器产生出来,这里必要决定于class不展现bitwise copy semantics.一个class object可以从两种方式复制得到,一种是被初始化,另一种是被指定,从概念上讲,这两个操作分别是以copy constructor和copy assignment operator.
  就像default constructor一样copy constructor没有声明一个copy constructor,就会有隐含声明(implicitly declared)出现,类似,copy constructor分为trivial和nontrivial两种,当class不展现bitwise copy semantics时,这个copy constructor为nontrivial.

...下列四种情况,一个class不展现bitwise copy semantics:
  1)当一个class内含一个member object而后者的class声明有一个copy constructor时(被设计者声明,或是由编译器合成).
  2)当class 继承自一个base class,而后者存在有一个copy constructor时(有设计者声明或是由编译器合成).
  3)当class 声明了一个或多个virtual functions时.
  4)当class派生自一个继承串连,其中有一个或是多个virtual base classes时.
  前两种情况,编译器必须将member或base class的"copy constructors 调用操作"安插到被合成的copy constructor中.
  对于第三,第四种情况,需要的操作:
    a)重新设定virtual table的指针.
    b)处理virtual base class subobject:virtual base class的存在需要特别处理,一个class object 如果以另一个object作为初值,而后者有一个virtual base class subobject,那么也会使"bitwise copy semantics"失效.
  总结:在以上四种情况下,class不在保持"bitwise copy semantics",而且default copy constructor如果未被声明的话,会被视为nontrivial.

关于copy constructor:
  copy constructor的应用,迫使编译器对你的代码做部分转化,尤其是当一个函数以传值的方式传回一个class object,而该class有一个copy constructor(被声明或是被合成出来)时,这将导致深奥的程序转化-不论在函数的定义或是使用上,此外编译器也将copy constructor的调用操作优化.


2.3成员初始化队伍:
...在下列四种情况下,必须使用member initialization list:
  1)当初始化一个reference member时.
  2)当初始化一个const member时.
  3)当调用一个base class的constructor,而它拥有一组参数时.
  4)当调用一个member class的constructor,而它拥有一组参数时.

...编译器会一一操作initialization list,以适当次序在constructor之内安插初始化操作,并且在任何explicit user  code之前.
  list中项目的次序是有class中的members声明次序决定,不是有initialization list中的排列次序决定(初始化次序和initialization list中项目次序错乱会产生一些问题).

...关于调用一个member function以设定一个member的初值:尽量使用"存在于constructor体内的一个member",而不要使用"存在于member initialization list中的member",来为另一个member设定初值.

原文地址:https://www.cnblogs.com/suiyu/p/2466466.html