器合成默认的构造函数或向已有的默认构造函数中插入代码的意义在于:使virtual函数机制(多态)可以正确地生效。
5、类带有一个virtual基类 这种情况是指类派生自一个继承串链,其中有一个或更多的virtual基类。
virtual基类的实现方法 在不同的编译器之间有极大的差异,但是每一种实现的共同点是必须使virtual基类在其每一个派生类对象中的位置,能够在执行期间准备妥当。
例如,对于以下的代码(并不是设计良好的代码):
class X
{
public:
X() {mData = 100;}
int mData;
};
class X1 : virtual public X
{
public:
X1() {mX1 = 101;}
int mX1;
};
class X2 : virtual public X
{
public:
X2() {mX2 = 102;}
int mX2;
};
class XX : public X1, public X2
{
public:
XX() {mXX = 103;}
int mXX;
};
int main()
{
cout << "sizeof(XX): " << sizeof(XX) << endl;
XX xx;
int *p = (int*) &xx;
for (int i = 0; i < sizeof(XX) / sizeof(int); ++i, ++p)
{
cout << *p << endl;
}
return 0;
}
在main函数中遍历并输出对象的内容,其运行结果如下:

从结果可以看到,即像在所有的类中都没有定义virtual函数,编译器还是会为子类XX插入了两个vptr,其中第一个vptr属于X1,第二个vptr属于X2。至于它有什么作用,我还不清楚,但是可以肯定的是编译器会为我们定义的构造函数安插必要的代码来实现virtual基类的机制。若类没有声明任何的构造函数,编译器必须合成一个默认构造函数来完成相同的操作。
注:若基类X中有virtual函数,则还会安插一个X::vptr,它的位置在100之前,即在基类X的成员变量之前。
6、总结
满足上述4种情况之一或以上的类,若没有声明任何的构造函数,编译器会为其合成一个默认的构造函数;若已声明一个或多个构造函数,则编译器会为每个构造函数安插一定的代码来完成编译必要的工作。这些被合成的构造函数称为implicit nontrivial default constructors(隐式有效的默认构造函数)。
不满足上述4种情况的类,而又没有声明任何构造函数,则该类拥有的是implicit trivial default constructors(隐式无效的默认构造函数),实际上不会被合成出来。
合成出来的默认构造函数,只会初化化基类子对象和成员类对象,其他的非static成员变量并不会被初始化。
此外,C++有两个常见的误解:
1)任何class如果没有定义默认构造函数,就会被合成出来。
2)编译器合成的默认构造函数,会显式设定class内每一个成员数据的默认值。