看看以下这段代码:
1 |
|
上述程序并不会合成出一个 default constructor。什么时候会合成出 default constructor 呢,下面分4种情况。
带有 Default Constructor 的 Memeber Class Object
编译器需要为该 class 合成一个 default constructor,不过这个合成操作只有在 constructor 真正需要被调用时才会发生。
合成的 default constructor、copy constructor、destructor、assignment copy operator 都以inline
方式完成,如果函数太复杂,不适合做成inline
,就会合成出 explicit non-inline static 实例。
举个例子:
1 |
|
编译器会为class Bar
合成一个 default constructor 来处理 Bar::foo
,但它并不初始化Bar::str
。
合成的 default constructor 可能像这样:
1 |
|
假设程序员提供了 default constructor:
1 |
|
则编译器会扩张已存在的 constructors:
1 |
|
如果有多个 class member objects 都要求 constructor 初始化操作,C++ 语言将以 member objects 在 class 中的声明顺序来调用各个 constructors。
带有 Default Constructor 的 Base Class
将会合成 Default Constructor,会根据 base class 声明的顺序调用 base class 的 default constructor。
如果有多个 constructors,编译器会扩张现有的每一个 constructors。
带有一个 Virtual Function 的 Class
以下两种情况,也需要合成出 default constructor:
- class 声明(或继承)一个 virtual function。
- class 派生自一个继承串链,其中有一个或更多的 virtual base classes。
举个例子:
1 |
|
编译期间发生两个扩张:
- virtual function table
- pointer member (也就是 vptr )
flip
函数可能被改写如下:
1 |
|
为了让这个机制发挥功效,编译器必须为每一个 Widget(或其派生类)object 的 vptr 设置初值,放置适当的 virtual table 地址。对于 class 所定义的每一个 constructor,编译器会安插一些代码来做这样的事情,如果没有 construcotr,则合成一个。
带有一个 Virtual Base Class 的 Class
例如以下代码:
1 |
|
foo()
可能被改写如下:
1 |
|
class 所定义的每一个 constructor,编译器会安插代码来初始化_vbcX
,如果没有 constructors,编译器必须合成一个 default constructor。
总结
C++ 新手一般有两个常见的误解:
- 任何 class 如果没有定义 default constructor,就会被合成出一个来。
- 编译器合成出来的 default constructor 会显式设定 class 内每一个 data member 的默认值。
如你所见,没有一个是真的。