问题:对c++初学者来说存在一个误区,如果类没有定义任何构造函数,编译器会自动生成默认的构造函数。
注意:这种说法是错误的。
正确的说法:惟有默认构造函数”被需要“的时候编译器才会合成默认构造函数。
那什么情况下是“被需要”的时候?
以下有四种情况编译器会自动合成default construct
情况1 含有类对象数据成员,该类对象类型有默认构造函数
即:一个clas含有类对象数据成员,该类对象类型有默认构造函数sA包含了一个对象成员objectB,而这个对象成员定义了(classB的)default constructor,那么编译器会为classA合成一个default constructor。
class A
{
public:
A()
{
cout << "A()" << endl;
}
};
class B
{
public:
A a;
int num;
};
void Test()
{
B b;
cout << b.num << endl; //<strong>注意合成的构造函数并不会初始化类中的内置类型复合类型的数据成员</strong>
//输出A()
}
结果输出 A() 表明 编译器会对B合成一个默认的构造函数
B()
{
a.A::A();
}
原因:因为类成员对象有默认构造函数,那么编译器就需要显式的来调用这个类成员对象的构造函数。而编译器想显式的调用类成员对象的默认构造函数,就需要自己来合成一些代码来调用。但是记住,编译器合成的默认构造函数仅仅调用类成员对象的默认构造函数,而不对我们类里面的其它变量做任何初始化操作。
情形2 基类带有默认构造函数的派生类
当一个类派生自一个含有默认构造函数的基类时,该类也符合编译器需要合成默认构造函数的条件。编译器合成的默认构造函数将根据基类声明顺序调用上层的基类默认构造函数。
原因:因为派生类被合成时需要显式调用基类的默认构造函数。
class Base
{
public:
Base(){ cout << "Base()" << endl; }
};
class Derived :public Base
{
public:
int d;
};
void Test2()
{
Derived d;
// 输出Base()
}
情形3 带有虚函数的类
类带有虚函数可以分为两种情况:
- (1)类本身定义了自己的虚函数
(2)
类从继承体系中继承了虚函数(成员函数一旦被声明为虚函数,继承不会改变虚函数的”虚性质“)。
这两种情况都使一个类成为带有虚函数的类。这样的类也满足编译器需要合成默认构造函数的类,原因是含有虚函数的类对象都含有一个虚表指针vptr,编译器需要对vptr设置初值以满足虚函数机制的正确运行,编译器会把这个设置初值的操作放在默认构造函数中。如果设计者没有定义任何一个默认构造函数,则编译器会合成一个默认构造函数完成上述操作,否则,编译器将在每一个构造函数中插入代码来完成相同的事情。
情形4 带有虚基类的类
虚继承也会在子类对象中被合成一个指向虚基类的指针,因此也要被初始化,所以必须要构造函数,虚基类或者虚继承保证子类对象中只有一份虚基类的对象。
总结一下: 不符合以上4种情形的而且没有声明任何构造函数的,编译器并不会合成默认的构造函数;
并且合成的默认构造函数并不会初始化类的内置类型复合类型的数据成员。