考虑如下代码:
class Foo {
public:
int val;
Foo *extent;
}
void foo_bar()
{
Foo bar;
// 要求bar's members都被清0
if(bar.val || bar.pnext){
// ...
}
}
上述代码语义是要求Foo
有一个default contructor
可以將它的两个members
初始化为0。可是编译器却不会为你做这件事情。
带有deafault constrcutor的member class object
如果一个class
没有任何constructor
,但它内含一个member object
,而后者有default constructor
,那么这个class
的implicit defautl constructor
就是nontrivial
编译器需要为该class
合成一个default constuctor
。考虑如下代码:
class Foo {
public:
int val;
Foo *extent;
Foo();
Foo(int) ...
}
class Bar {
public:
Foo foo;
char *str;
}
void foo_bar()
{
Bar bar;
// 要求bar's members都被清0
if(bar.str){
// ...
}
}
被合成的Bar defautl constructor
内含必要的代码,能够调用class Foo
的default constructor
来处理member obejct Bar::foo
;被合成的default constructor
看起来像这样:
inline Bar::Bar() {
// 伪代码
foo.Foo::Foo();
}
如果有多个class member objects
都要求constructor
初始化操作,将如何?C++
语言要求以members objects
在class
中的声明顺序来调用各个constructors
。考虑如下代码:
class Dopey {public: Dopey();};
class Sneezy {public: Sneezy(); Sneezy(int);};
class Bashful {public: Bashful();};
class Snow_White {
public:
Dopey dopey;
Sneezy sneezy;
Bashful bashful;
private:
int mumble;
}
如果Snow_White
没有定义default constructor
,就会有一个nontrivial constructor
被合成出来,依序调用Dopey, Sneezy, Bashful
的default constuctors
,然后如果Snow_White
定义了如下的default constructor
Snow_White::Snow_White() : sneezy(1024) {
mumble = 2048;
}
它会被扩张为:
Snow_White::Snow_White() : sneezy(1024) {
// 附件的compiler code
dopey.Dopey::Dopey();
sneezy.Sneezy::Sneezy();
bashful.Bashful::Bashful();
mumble = 2048;
}
带有Default Constructor的Base Class
如果一个没有任何constructor
的class
派生自一个带有default constructor
的bass class
,那么这个derived class
的default constructor
会被视为nontrivial
,并因此需要被合成出来
带有一个Virtual Function的Class
另外有两种情况,也需要合成出default constructor
class
声明一个virtual function
class
派生自继承串链,其中有一个或更多的virtual base classes
考虑如下代码:
class Widget {
public:
virtual void flip() = 0;
};
void flip(const Widget& widget) {widget.flip();}
// 假设Bell和Whistle都派生自Widget
void foo() {
Bell b;
Whistle w;
flip(b);
flip(w);
}
下面两个扩张行动会在编译期发生:
- 一个
virtual function table
会被编译器产生出来,内放class
的virtual functions
地址 - 在每个
class object
中,一个额外的pointer member
会被编译器合成出来,内含相关的class
带有一个Virtual Base Class的Class
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;}
int main() {
foo(new A);
foo(new C);
}