1. 存在错误的程序例子
class Foo { public: int m_nVal; Foo *m_pNext; }; void Foo_Bar( void ) { Foo bar; if ( bar.m_nVal || bar.m_pNext ) { int i; i++; } }
(1)正确的程序语意是要求 Foo 有一个 default constructor,可以将 members 初始化为0。
(2)上述代码不会合成一个 default constructor,即使编译器有需要而合成一个 constructor,也只执行编译器所需的操作,而不会把 members 初始化为0。
(3)改正方法是,程序员提供一个 default constructor,并把 members 初始化。
2. C++ Standard[ISO-C++95] 的 Section 12.1
对 class X,没有 user-declared constructor,则会有一个 default constructor 被 implicitly(隐含) 声明出来,这个 constructor 是 trivial(没有用的) 的。
3. 带有 “default constructor” 的 member class object
(1)一个 class 没有 constructor,但有一个 member object,后者有 default constructor,则这个 class 的 implicit default constructor 就是 nontrivial。编译器只有在 constructor 真正需要被调用时合成一个 default constructor。
(2)为避免在不同的编译模块中合成多个 default constructor,合成的 default constructor、copy constructor、destructor、assignment copy operator 都以 inline 方式合成。不适合做成 inline 时,会合成一个 explicit non-inline static 实体。
(3)案例分析
class Foo { public: Foo(); }; class Bar { public: Foo m_foo; int m_pVal; }; void Func( void ) { Bar bar; // Bar::m_foo 此处需被初始化 } // 被合成的 default constructor inline Bar::Bar( void ) { // 调用 class Foo 的 default constructor。初始化 Bar::m_foo 是编译器的责任。 m_foo.Foo::Foo(); // m_pVal 不会被初始化。是程序员的责任。 } // 存在 user-declared constructor 时, // constructor 会被扩张,在 user code 前,以“member 声明次序”调用必要的 default constructors Bar::Bar( void ) { m_foo.Foo::Foo(); m_pVal = NULL; }
4. 带有“default constructor”的 base class
(1)一个没有 constructor 的 class 派生自带有 default constructor 的 base class,则这个 derived class 的 default constructor 是 nontrivial,且需要被合成。将调用 base class 的 default constructor。对后继派生的 class,这个合成的 constrcutor 相当于 user-declared constrcutor。
(2)有多个 constructor,但是没有 default constructor 时,编译器会扩展现有的每一个 constructor,添加所需要的 member default constructor,而不会合成 default constructor。
(3)先调用 base class constructor,后调用 member class objects 的 default constructors。
5. 带有一个“vritual function”的 class
(1)两种情况下,也需要合成 default constructor
a. class 声明(或继承)一个 virtual function。
b. class 派生自一个继承串链其中有一个或更多的 virtual base class。
(2)案例分析
class Widget { public: virtual void flip(void) = 0; }; void flip( const Widget &widget ) { // 此操作被重写,( *widget.vptr[1] )( &widget ) // “1”表示 flip() 在 vtbl 中的索引。 // &widget 表示要交给“被调用的某个 flip() 函数实体”的 this 指针。 widget.flip(); } void Func( void ) { Bell b; // Bell、Whistle 继承 Widget Whistle w; flip(b); flip(w); }
编译期间会发生两个扩展操作:
a. 一个 vtbl 被编译器产生,放 class 的 virtual functions 的地址。
b. 每个 class object 中,一个 vptr 被编译器合成,放 vtbl 的地址。
对 class 的每个 user-delcared constructor,编译器会添加一些代码来完成这两个操作。
而没有任何 constructor 时,编译器会合成 defalut constructor,来正确初始化 vptr。
6. 带有一个“virtual base class”的 class
(1)virtual base class 的实现法在不同的编译器间有极大的差异。但是每种实现法的共同点是必须使 virtual base class 在其每一个 derived class object 中的位置,能够在执行期间准备妥当。
7. 总结
(1)四种情况下,编译器会为未声明 constructor 的class 合成一个 default constructor。
(2)C++ standard 把那些合成物称为 implicit nontrivial default constrcutors。
(3)被合成的 constructor 只能满足编译器的需要,是借助“调用 member object 或 base class 的 default constructor”、“为每个 object 初始化 virtual function 机制或 virtual base class 机制”而完成的。
(4)对不存在那四种情况,有没有任何 constructor 的 class,拥有的是 implicit trivial defatule constructor,实际上不会被合成出来。
(5)在合成的 default constructor 中,只有 base class subobjects 和 member class objects 会被初始化,其他 nonstatic data members 不会被初始化。