implicitly d
efault constructor
对于
class X ,如果没有任何User-declared constructor,那么会有一个default constructor被隐式(implicitly)声明出来....一个被隐式声明出来的default constructor将是一个trivial(浅薄而无能,没啥用的)constructor.
class Foo{
public :
int val;
Foo * pnext;
}
被合成出来的constructor只执行编译器所修的行动,也就是说,即使是需要为class Foo合成一个default constructor,那个constructor也不会将两个data member val和pnext初始化为0.
带有Default Constructor的member class object
如果一个class 没有任何constructor,但它内涵一个member Object ,而后者有default constructor,那么这个class的implicit default constructor就是 有用的。但是编译器不会帮初始化其他非Object成员,或者没有default constructor函数的member Object。
在C++各个不同的编译模块中,编译器如何避免合成多个default constructor呢?解决办法是把合成的default constructor,copy constructor ,destructor,assignment copy operator都以inline方式完成。
一个inline函数有静态链接,不会被文件以外者看到,如果函数太复杂,不适合做成inline,就会合成出一个explicit non-inline static 实例。
以下程序片段,编译器为class Bar合成一个default constructor:
class Foo{public:Foo();Foo(int),.....}
class Bar{public Foo foo; char *str;}
void foo_bar()
{
Bar bar;//Bar::foo必须在此处初始化。Bar::foo是一个member Object而其class Foo拥有default constructor。
if(str){......}
}
这里被合成的Bar default constructor内含必要的代码,能够调用class Foo的default constructor来处理member Object Bar::foo,但是它并不产生任何代码来初始化Bar::str.将Bar::foo初始化是编译器的责任,将Bar::str初始化则是程序员的责任,被合成的default constructor看起来可能像这样:
//Bar 的default constructor可能会像被这样合成
//为member foo 调用class Foo的default constructor
inline
Bar::Bar()
{
//C++伪代码
foo.Foo::Foo();
}
再一次注意,被合成的default constructor只满足编译器的需要,而不是程序的需求,为了让这个程序片段能够被正确执行,字符指针str也需要被初始化。
我们假设程序员经由下面的default constructor提供了str的初始化操作:
//程序员定义的default constructor
Bar::Bar(){str = 0}
现在程序的需求已经满足了,但是编译器还需要初始化member Object foo.
由于default constructor已经被显式地定义出来,编译器没法合成一个,那么编译器会采取什么行动呢?
编译器的行动是:
如果class A内含一个或一个以上的member class Object,那么class A的每一个constructor必须调用每一个member class的default constructor。编译器会扩张已存在的constructor,在其中安插一些代码,使得User code在被执行之前,先调用必要的default constructors.延续前一个例子,扩张后的constructor可能像这样:
//扩张后的default constructor
//C++伪代码
Bar::Bar()
{
foo.Foo::Foo();//附加上的compiler code
str = 0 ; //explicit User code
}
如果有多个class member Object都要求constructor初始化操作,将如何?
C++语言要求以“member object在class中声明顺序“来调用各个constructor。这一点由编译器完成,它为每一个constructor安插程序代码,以”member声明顺序“调用每一个member所关联的default constructor,这些代码将被安插在explicit User code之前。
eg:
class Dopey{ public :Dopey();......};
class Sneezy{public: Sneezy();Sneezy(int);.....};
class Bashful{public: Bashful();....};
以及一个class Snow_White:
class Snow_White{
public:
Dopey dopey;
Sneezy sneezy;
Bashful bashful;
//....
private :
int numble;
};
如果Snow_White没有定义default constructor,就会有一个nontrivial constructor被合成出来,依序调用Dopey,Sneezy,Bashful的default constructor。然而如果Snow_White定义了下面这样的default constructor:
Snow_White::Snow_White():sneezy(1024){
numble = 0;
}
它会被扩张成:
//编译器扩张后的default constructor
// C++伪代码
Snow_White::Snow_White():sneezy(1024)
{
//插入member class Object
//调用其constructor
dopey.Dopey::Dopey();
sneezy.Sneezy::Sneezy(1024);
bashful.Bashful::Bashful();
//explicit user code
numble = 0 ;
}