C++ 默认构造函数

先说C++新手一般的误解:

1.任何一个类如果没有定义默认构造函数,编译器会自动合成一个默认构造函数。

2.编译器合成出来的默认构造函数,会显式的设定类中成员变量的值。

先看一个最基本的例子:


从图中可以看到对象a并没有被初始化,即编译器没有为类A合成一个默认构造函数。其实C++标准委员会曾叙述,如果没有任何用户声明的构造函数,那么会有一个默认构造被隐式构造出来,但是这个隐式声明出来的默认构造函数将是一个trivial(浅薄无能的,没啥用的)构造函数。

下面说在哪几种情况下编译器会自动合成默认构造函数(共四种情况):

情形一:

当成员变量中有一个或多个类的对象,且该对象带有默认构造函数,这时编译器需要为该类合成一个默认构造函数,不过这个合成操作只有在构造函数真正被调用时才会发生,(即构造对象时)。


从图中可以发现,此时没有报错,且a.x被输出了一个随机值,可以说明编译器的确为A类合成了默认构造函数,但并没有给成员变量赋予一个初值。合成操作只是为了满足编译器的需要,而不是程序的需要,所以为了程序可以正确的 执行,还需要程序员手动初始化里面的成员变量。假设A::A(){x=0; p=0;} 此时程序员手动定义了一个默认构造函数,那编译器就不会再合成第二个了。此时你可能会问:编译器会采取什么行动呢?

实际上,如果类A包含一个或一个以上成员类对象(member class object),那么类A的每一个构造函数都必须调用每一个成员类对象的默认构造函数。即编译器会自动扩张构造函数,扩张后的C++伪码为:

A::A()
{    //在自定义的默认构造函数后进行扩张,扩张后的默认构造函数伪码:
	b.B::B();
	x = 0;
	p = 0;
}

如果有多个类成员对象,则按照声明顺序来依次调用它们各自的默认构造函数。

情形二:带有默认构造函数的基类


与情形一类似,如果基类带有默认构造函数,那这个派生类也需要合成一个默认构造函数,且派生类的默认构造函数中需要先调用基类的构造函数。如果设计者自定义了多个构造函数,但是没有默认构造函数,则编译器会扩张现有的每一个构造函数,将所有成员类对象的默认构造函数安插进去,同情形一。

情形三:带有虚函数的类

分为两小类情形:1)class 声明或继承了一个虚函数

                           2) class派生自一个继承串链,其中有一个或多个虚函数


带有虚函数时会有两个扩张行为:1)虚函数表(vtbl)会被编译器产生出来,内放class里的虚函数地址。2)每一个class object中都会有一个额外的指向虚函数表的指针(vptr)被编译器合成出来。

情形四:带有虚基类的类


对于虚继承的类中都会安插一个_vbcX指向虚基类X

猜你喜欢

转载自blog.csdn.net/hlw0522/article/details/80102412