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。this
(3)改正方法是,程序員提供一個 default constructor,並把 members 初始化。spa
2. C++ Standard[ISO-C++95] 的 Section 12.1指針
對 class X,沒有 user-declared constructor,則會有一個 default constructor 被 implicitly(隱含) 聲明出來,這個 constructor 是 trivial(沒有用的) 的。code
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 實體。ip
(3)案例分析ci
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 不會被初始化。