导航

Default Constructor的构造操作

Posted on 2013-06-17 16:54  吴豪  阅读(1201)  评论(0编辑  收藏  举报

Default Constructor的构造操作

       C++ Annotated Reference Manual书中的Section 12.1说过:default constructor 只有在编译器需要的时候才会被编译器合成出来。

       C++ Standard修改了C++ ARM的说法,但实际上的行为是一样的。C++ Standard[ISO-C++95]的Section 12.1说到:对于class X,如果没有任何user-declared constructor,那么会有一个default constructor被隐式(implicitly)声明出来。不过这样的隐式声明的default constructor将是一个trivial(无用的)constructor。也就是所谓的implicit trivial default constructor,它们实际上并不会被合成出来。

       那到底声明才是C++ ARM所说的编译器需要的情况呢?

第一,“带有Default Constructor”的Member Class Object

       如果一个class X没有任何constructor,但它有至少一个member object,而这个member object对应的class有default constructor,那么编译器就需要为class X合成一个default constructor。不过这个合成操作只有在constructor被调用的时候才会发生。

       举个例子:

       class Foo { public : Foo(), Foo(int)…};

       class Bar {pubcli Foo foo; char *str;};

 

       void foo_bar()

       {

              Bar bar; // Bar:foo 必须在此处初始化。

}

 

被合成的default constructor看起来可能像这样(省略this指针):

inline

Bar::bar()

{

       foo.Foo::Foo();

}

 

第二,“带有Default Constructor”的Base Class

       与第一点类似,如果一个没有任何constructor的class派生自一个“带有Default Constructor”的base class,那么编译器会为这个derived class合成一个default constructor,它将调用上一层base classes的default constructor(根据它们声明顺序)。如果同时存在第一点和第二点的情况,则member class objects constructor会在所有base class constructor之后再调用。

 

第三,“带有至少一个Virtual Function”的Class

       编译器会为每一个“带有至少一个Virtual Function”的class object的vptr(指向virtual table)设定初值。对于一个没有任何constructor的class,编译器会为它合成一个default constructor,以便正确地初始化每一个class object的vptr。

 

第四,“带有至少一个Virtual Base Class”的Class

       Virtual base class的实现法在不同的编译器之间有极大地差异。然而,每一种实现法的共同点在于必须使virtual base class在其每一个derived class object中的位置,能够于执行期准备妥当。

       举个例子:

       class X { public: int i;};

       class A : public virtual X {public: int j;};

       class B : public virtual X {public: double d;};

       class C : public A, public B {public: int k;};

 

       // 无法在编译期决定pa->X::i的实际偏移位置

       void foo(const A* pa) {pa->i = 1024;}

 

       main()

       {

              foo(new A);

foo(new B);

}

编译器无法固定住foo()之中“经由pa而存取的X::i”的实际偏移位置,因为pa的真正类型可以改变。编译器必须改变“执行存取操作”的那些代码,使X::i可以延迟至执行期才决定下来。

对于一个没有任何constructor的class,编译器会为它合成一个default constructor,在这个default constructor中会安插那些“允许每一个virtual base class的执行期存取操作”的代码。

 

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

 

注意

1、在合成的default constructor中,只有base class subobjects和member class objects会被初始化。所有其他的nonstatic data member(如整数,整数指针,整数数组等等)都不会被初始化。这些初始化操作对于编译器都是非必要的,提供这些初始化操作的应该是程序员而不是编译器。

2、不是任何没有定义default constructor的class都会生成一个implicit default constructor。

3、编译器合成的default constructor不会显示设定“class 内每一个data member的默认值”。