深度探索c++对象模型
第2章 构造函数语义学
2.1 Default Constructor的构建操作
class Foo{
public: int val; Foo *pnext;};
void foo_bar(){
// 程序需要bar's members都被清零
Foo bar;
if(bar.val || bar.pnext)
// ...do something
}
上面例子中,程序语义需要Foo有一个default constructor,可以将它的两个members初始化为0。但是上述程序并不会合成一个default constructor。
Q:什么时候才会合成一个default constructor?
Ans:当编译器需要它的时候!此外,被合成的constructor只执行编译器所需的行动。为了让上一段程序正确运行,必须提供一个明显的default constructor,将两个members适当的初始化。
对于class X,如何没有任何的user-declared constructor,那么会有一个default constructor被暗中(implicitly)声明出来……一个被暗中声明出来的default constrtuctor将是一个trivial(没用的) construct……被编译器需要的是nontrivial default constructor。
下面讨论nontrivial default constructor的四种情况。
1.“带有Default Constructor"的Member Class Object
如果一个class没有任何constructor,但它内含的一个member object有default constructor,那么这个class的implicit default constructor就是”nontrivial“,编译器需要为此class合成出一个default constructor,不过这个合成操作只有在constructor真正需要被调用时才会发生。
class Foo {
public: Foo(), Foo(int)...};
class Bar {
public: Foo foo; char *str;} //不是继承,是内含
void foo_Bar(){
//Bar::foo是一个member object,其class Foo拥有default constructor
Bar bar; //Bar::foo必须在此初始化。
if(str){
}...
}
被合成的Bar default constructor内含必要的代码,能够调用class Foo的default constructor来处理member object Bar::foo,但它并不产生任何代码来初始化Bar::str,将Bar::foo初始化是编译器的责任,将Bar::str初始化则是程序员的责任。被合成的default constructor看起来可能像这样:
// 被member foo调用class Foo的default constructor
inline Bar::Bar()
{
//c++伪代码
foo.Foo:Foo();
}
上面只是满足了编译器的需要,而不是程序的需要。为了让程序正常执行,字符指针str也需要被初始化。
//程序员定义的default constructor
Bar::Bar() {
str=0;}
此时编译器采取的行动:”如果class A内含一个或一个以上的member class objects, 那么class A的每一个constructor必须调用每一个member classes的default constructor“。编译器会扩张已存在的constructors,在其中安插一些代码,使得user code被执行前,先调用必要的default constructors.
//扩张后的default constructor
//c++伪码
Bar::Bar()
{
foo.Foo::Foo(); //附加上的complier code
str = 0;
}
再举一例:
class Dopey {
public: Dopey(); ...};
class Sneezy {
public: Sneezy(int); Sneezy(); ...};
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 constructors,如果Snow_White定义了下面这样的default constructor:
//程序员写的
Snow_White::Snow_White():sneezy(1024){
mumble=2048;
}
它会被扩张为
Snow_White::Snow_White():sneezy(1024){
//插入member class object,调用其constructor
dopey.Dopey::Dopey();
sneezy.Sneezy::Sneez