编译器与默认构造函数

来源:互联网 发布:1024最新 知乎 编辑:程序博客网 时间:2024/05/01 11:40
 

C++新手一般有两个常见的误解:

a.       任何一个class如果没有定义default constructor,就会被合成一个出来

b.       编译器合成出来的default constructor会明确设定class内每一个data member的默认值。

 

对于问题1,C++ Standard规定:

对于class X, 如果没有任何user-declared constructor, 那么会有一个default constructor被implicitly 声明出来, 一个被暗中声明出来的default constructor,将是一个trivial constructor, 即,在函数体内没有逻辑的处理,连赋值都没有。而这样的constructor,编译器实际上并不会真的把他们合成出来。

 

对于问题2,C++ Standard规定:

在合成default constructor时,只有关于class object的部分会被初始化,所有其他的nonstatic data member,都不会被初始化,因为这些对编译器来说不是必要的。

 

那么什么时候,编译器必须要合成一nontrivial的default constructor呢?

 

(1)如果class A内含一个的member class object B, 且该B带有自定义的default constructor。

很明显,如果编译器认为class A声明的还是trivial constructor, 那么编译器就不可能用通用的语意,来构造B, 因为B的default constructor很可能带有自定义逻辑,是nontrivial,必须被调用,这与在函数体内没有逻辑的处理,连赋值都没有是冲突的。

那么就必须在构造时,为A合成一个default constructor,在合成的函数体内包含能够调用B的default constructor,如果有多个member objects, 那么C++语言要求以member objects在class 中的声明次序,来调用各个default  constructors。

 

(2)如果一个没有任何constructors的class A派生自一个“带有default constructor”的base class C

很明显,如果编译器认为class A声明的还是trivial constructor, 那么编译器就不可能用通用的语意,来构造基类C, 因为C的default constructor很可能带有自定义逻辑,是nontrivial,必须被调用,这与在函数体内没有逻辑的处理,连赋值都没有是冲突的。

那么就必须在构造时,为A合成一个default constructor,在合成的函数体内包含能够调用C的default constructor, 需要注意的是,如果A提供多个constructors,但其中都没有default constructor,那么编译器会扩张现有的每一个constructors,将“用以调用所有必要之default constructors”的代码加进去,而不会合成一个新的default constructor.

 

(3)class声明或继承一个virtual function

由于一个virtual function table -- vptr, 会被编译器产生出来,内放class的virtual functions地址。

为了给vptr设定初始,放置适当的virtual table地址,编译器会为他们合成一个默认构造函数,以便正确的初始化每一个class object的vptr.

 

(4) class派生自一个继承串链,其中有一个或更多的虚基类

所有经由reference或pointer来存取一个virtual base class的操作,都可以通过为每一个virtual base classes 安插一个指针,来完成。这个工作由编译器为构造函数合成。

 

综上所述,如果编译器认为,当前默认构造函数不需要添加任何逻辑操作,就不会被合成,否则,就在调用时,被合成出来。

参考自

C++ Object Model --- The Semantics of Constructors

原创粉丝点击