【C++】深度探索C++对象模型读书笔记--构造函数语义学(The Semantics of constructors)(一)

Default Constructor的构造操作

  对于class X,如果没有任何user-declared constructor, 那么会有一个default constructor被隐式(implicit)声明出来,一个被隐式声明出来的default constructor将是一个trivial consructor......

  下面讨论nontrivial default constructor的4种情况。

  1.带有Default Constructor的Member Class Object

    如果一个class没有任何constructor,但它内含有一个member object,而后者有default constructor,那么这个class的implicit default constructor就是“nontrivial”,编译器需要为该class合成出一个default constructor。不过这个合成操作只有在constructor真正被调用时才会发生。

     如果有多个class member objects都要求contructor初始化操作。C++语言要求以“member objects在class中的声明顺序“来调用各个constructors。这一点由编译器完成,它为每个constructor安插程序代码,以”member声明顺序“调用每一个member所关联的default constructors。这些代码将被安插在explicit user code之前。举个例子,假设我们有以下三个classes:

  

class Dopey {public: Dopey();...};
class Sneezy {public: Sneezy(int); Sneezy();...};
class Bashful {public: Bashful();...};

以及一个class Snow_White:
class Snow_White {
public:
    Dopey dopey; 
    Sneezy sneezy;
    Bashful bashful;

private:
    int mumble;
};

  如果Snow_White没有定义default constructor,就会有一个nontrivial constructor被合成出来,依序调用Dopey、Sneezy、Bashful的default constructors。然而如果Snow_White定义了下面这样的default constructor:

  

//程序员所写的default constructor
Snow_White::Snow_White(): sneezy(1024)
{
    mumble = 2048;
}

  它将会被扩张为:

  

//编译器扩张后的default constructor
Snow_White::Snow_White():sneezy(1024)
{
    //插入member class object
    //调用其constructor
    dopey.Dopey::Dopey();
    sneezy.Sneezy::Sneezy(1024);
    bashful.Bashful::Bashful();

    //expilict user code
    mumble = 2048;
}

  

  2."带有Default Constructor“的Base Class

    类似的道理,如果没有任何constructors的class派生自一个”带有default constructor“的base class,那么这个derived class的default constructor会被视为nontrivial,并因此需要被合成出来。它将调用上一层base classes的default constructor(如果是多继承,根据他们声明的顺序)。对一个后继的class而言,这个合成的constctor和一个”被显式提供的default constructor“没有什么差异。

    如果设计者提供多个constructors,但其中都没有default constructor呢?编译器会扩张现有的每一个constructors,将“用以调用所有必要之default constructors”的程序代码加进去。它不会合成一个新的default constructor,因为其他“由user所提供的constructors”存在的缘故。如果同时亦存在着“带有default constructor”的member class objects,那些default constructor也会被调用--在所有base class constructor之后。

  

  3.“带有一个virtual Function”Class

    另有两种情况,也需要合成出default constructor:

    1. class声明(或继承)一个virtual function  

    2. class继承自一个继承串链,其中有一个或多个的virtual base classes。

    假设类中还有虚函数,编译期间会发生两步扩张活动:

    1. 一个virtual function table(在cfont中被称为vtbl)会被编译出来,内放class的virtual functions地址。

    2. 在每个class object中,一个额外的pointer member(也就是vptr)会被编译器合成出来,内含相关之class vtbl的地址。

    对于那些未声明任何constructors的classes,编译器会为它们合成一个default constructor,以便正确地初始化每一个class object的vptr

  4.“带有一个virtual Base Class”的Class

  

  总结:有4种情况,会造成“编译器必须为未声明constructor 的classes合成default constructor”。它们分别是:

    “带有Default Constructor”的Member Class Object

    “带有Default Constructor”的Base Class

    “带有一个Virtual Function”的Class     

    “带有一个Virtual Base Class”的Class

    C++Standard把那些合成物称为implicit nontrivial default constructors。被合成出来的constructos只能满足编译器(而非程序)的要求。它之所以完成任务,是借着“调用member object或base object的default constructor”或是“为每一个object初始化其virtual function机制或virtual base class机制”而完成的。至于没有存在那4种情况而又没有声明任何constructor的classes,我们说它们拥有的是implicit trivial default constructors,它们实际上并不会被合成出来。

    在合成default constructor中,只有base class constructor和member class objects会被初始化。所有其他的nonstatic data member(如整数,整数指针、整数数组等等)都不会被初始化。这些初始化操作对程序而言或许有需要,但对编译器则非必要。如果一程序需要一个“把某指针设为0”的default constructor,那么提供它的人应该是程序员。

    C++新手一般有两个常见的误解:

    1. 任何class如果没有定义default constructor,就会被合成出一个来。

    2.编译器合成出来的default constructor会显式设定“class内每一个data member的默认值”  

    如你所见没一个是真的。