合成默认构造函数的4种情况(合成是为了满足编译器的需要,而不是程序的需要)
1. "带有Default Constructor"的Member Class Object
class Foo
{
public:
Foo();
Foo(int);
}
//Bar包含Foo
class Bar
{
public:
Foo foo;
char *str;
}
void foo_bar()
{
Bar bar; //Bar::foo 必须在此处初始化。
}
//被合成的Bar default constructor内含必要的代码,能够调用class Foo的default construct来处理member object Bar::foo,<br>
//但它并不产生任何代码来初始化Bar::str()将Bar::str初始化则是程序员的责任。
//Bar的default constructor可能会被这样合成
//为member foo调用Class Foo的default constructor
inline Bar::Bar()
{
//C++伪代码
foo.Foo::Foo();
}
假设程序员经由下面的default constractor提供了str的初始化操作
//程序员定义的default constructor
Bar::Bar()
{
str = 0;
}
编译器的行动是:“如果class A内含一个或一个以上的member class objects, 那么class A的每一个constructor必须调用每一个member classes的default constructor",编译器会扩张已存在的constructor,在其中安插一些代码,使得user code被执行之前,先调用必要的default constructor。
//扩张后的default constructor
//C++伪代码
Bar::Bar()
{
foo.Foo::Foo();
str = 0;
}
2. "带有Default Constructor"的Base Class。
如果一个没有任何constructors的class派生自一个“带有default constructor”的base class,那么这个derived class 的default constructor会被视为nontrivail,因此需要被合成。
如果设计者提供多个constructor,但其中都没有default constructor呢?编译器会扩张现有的每一个constructor,将“用以调用所有必要之default constructors”的程序代码加进去。
3. "带有一个virtual Function"的Class
两种情况需要合成default constructor
- class声明(或继承)一个virtual function.
- class派生自一个继承串链,其中有一个或更多的virtual base classes.
下面两个扩张行动会在编译期间发生:
- 一个virtual function table会被编译器产生出来,内放class 的 virtual function地址。
- 在每一个class object中,一个额外的pointer member(也就是vptr)会被编译器合成出来,内含相关之class vtbl的地址。
编译器为每一个带有virtual function类的vptr设定初值,放置适当的virtual table地址。对于class所定义的每一个constractor,编译器会安插一些代码来做这样的事情,对于没有没有声明任何constructor的classes,编译器会为他们合成一个default constructor.
4. "带有一个Virtual Base Class"的Class
对于class所定义的每一个constructor,编译器会安插那些"允许每一个virtual base class的执行期存取操作"的代码,如果class没有任何constructors,编译器必须为它合成一个default constructor。