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的默认值”。