谈什么情况下C++编译器会自动生成default constructor

来源:互联网 发布:python源代码下载 编辑:程序博客网 时间:2024/06/05 20:04

最近读到Lippman的《深度探索C++对象模型》,对类的知识又复习了一遍。这次就先写个default constructor吧。

对于C++新手来说,一个常见的误区是:如果一个class没有定义任何的constructor,那么编译器将会生成一个default constructor。然而,事实并不总是如此,下面就列举编译器会自动合成default constructor的情况:
“当编译器需要default constructor的时候,它才会自动合成一个”
1、“带有default constructor”的member class object;
2、“带有default constructor”的base class;
3、“带有一个virtual function”的class;
4、“带有一个virtual base class”的class;

下面一一介绍它们:
情形1、“带有default constructor”的member class object:即一个classA包含了一个对象成员objectB,而这个对象成员定义了(classB的)default constructor,那么编译器会为classA合成一个default constructor。请看如下代码:
class B{B(){};…};
class A{ public: B b; //对象成员};

int main (){
A a; //对象b需要在此时初始化。
…}
在classA中包含的对象成员b必须在对象a创建时初始化,这需要调用classB的constructor,而classA并没有constructor,编译器会为其合成一个,但其行为只包含调用classB的default constructor以初始化对象b(并不会初始化classA中的非对象数据成员)。给出调试实例:
代码为
运行结果:
可以看到,classB的default constructor被调用了,而编译器合成的classA的constructor并没有将double d初始化(d为系统遗留的值)。如果classA含有多个对象成员,则将依次调用它们的default constructor。

情形2、“带有default constructor”的base class;
这里指的是classDerived继承自classBase,前者没有default constructor而后者有的情况。虽然这里是继承而情形1是包含,但其实个中道理是相同的,创建classDerived的对象时,其中的继承的classBase部分需要被初始化,将合成一个classDerived的defaultconstructor来调用基类的构造函数,同样地,这个default constructor不初始化classDerived的其他数据成员:
class Base{ Base(){};…};
class Derived:public Base{public: double d;…};

int main(){
Derived D;//classBase的成分需要被初始化。
…}

**在讲接下来两种情形之前,先要补充一下virtual function table的概念,如果一个classX的结构为:
class X{
virtual ~X(){};
virtual void vf(){};
private:
//data members

那么classX将持有一个_vptr(虚函数表指针)指向vtbl:
classsX–>_vptr–>vtbl:
[0]info_of_class X;
[1]~X();
[2]vf();
而且继承自classX的派生类都将含有一个_vptr,且含有一个bptr,指向基类的base class table。**

情形3、“带有一个virtual function”的class;
这里有两种情况:
3.1class声明(或继承)一个virtual function。
3.2class派生自一个继承串链,其中有一个或更多的virtual base class。
看书上的代码:
class Widget{
public:
virtual void flip()=0; //pure virtual function;
//…
};
class Bell :public Widget{//…};
class Whistle : public Widget{//…};

void flip(const Widget& widget){widget.flip();}

void foo(){
Bell b;
Whistle w;

flip(b);
flip(w);
}

这时,一个vtbl会被编译器产生出来,存放virtual functions的地址;并在每个class object中插入一个vptr,指向与之相关的class vtbl。
foo函数中的flip(b)等价调用操作为:
flip(const Widget& widget){(*widget.vptr[1])(&widget);}
即:flip(const Widget& b){(*widget.vptr[1])(&b);}
其中的索引1为class member function flip()在vtbl中的索引。
由于需要用到virtual function table和vptr,这个类对象的vptr需要在对象创建时初始化,故编译器会合成一个default constructor。
//(小弟才疏学浅,如有差错,还请指出)
简单运行示例(没想到怎么检验。。):
代码
运行结果

情形4、“带有一个virtual base class”的class;
virtual base class 有多种实现方式,例如在derived class中插入指针指向base class的部分;每一种实现法的共同点在于必须使virtual base class在其每一个derived class object中的位置,能够在执行期准备妥当。这有点类似于情形2(初始化基类成分),也有点类似情形3(初始化vtbl和vptr)。

以上情形的机制是:“调用member object或者base class的default constructor“或是”为每一个object初始化其virtual function机制或者virtual base class机制”。
不符合以上4种情形的而且没有声明任何constructor的class,并不会合成default constructor;且符合情形而合成出来的默认构造函数,只初始化base class subobject和member class objects,而不初始化nonstatic data member。这也是C++新手的第二个误区:编译器合成出来的default constructor会显式地设置“class内的每一个data menber 的默认值”。

有疑问或者高见欢迎跟我交流,大家一起成长!谢谢!

1 0
原创粉丝点击