• 《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设定初值.

  • 相关阅读:
    Google笔试题
    OpenStack Ceilometer简介
    OpenStack Object Storage(Swift)架构、原理及特性
    【大话存储2读书笔记】磁盘IO的重要概念
    递归,汉诺塔游戏
    函数定义与使用
    字符串操作
    for循环:用turtle画一颗五角星
    列表、元组、字典、集合的定义、操作与综合练习
    npm 相关
  • 原文地址:https://www.cnblogs.com/suiyu/p/2466466.html
Copyright © 2020-2023  润新知