標籤:tab 例子 處理 初始化 自己 font user next 聲明
在不聲明自訂建構函式時,編譯器會自動產生一個預設建構函式。但是這個預設建構函式有可能是一個trivial(無用的) constructor,也可能是nontrivial constructor。
舉個例子
class Foo { public: int val; Foo* pnext; } void foo_bar(){ Foo bar; if(bar.val || bar.pnext) //...do something }
之前的想法是Foo有一個預設建構函式,可以將var和pnext初始化為0。
其實不然。
原因是將兩個members初始化為0,並不是編譯器所需要的。也就是說,編譯器合成了一個預設建構函式是trivial constructor,不會對兩個members做初始化。
那麼什麼情況下,編譯器會合成nontrivial constructor?四種情況。
1、帶有Default Constructor的Member Class Object
類中的一個member object有default constructor。
class Foo {public: Foo(); Foo(int);} class Bar {public: Foo foo; char* str;}
當建立Bar對象時,需要調用Bar的預設建構函式。被合稱的預設建構函式需要能夠調用Class Foo的 的預設構造,處理Bar::foo。
但是它並不產生任何代碼初始化Bar::str。正如前面所說,初始化foo是編譯器的責任,初始化str是程式員的責任。
如果為了初始化str,我們定義自己的建構函式:
Bar::Bar() {str = 0;}
此時編譯器不會為我們合成預設建構函式,那麼是如何?上面的初始化foo的工作呢?
原來編譯器會擴張已存在的constructors,在其中安插代碼,在user code之前,根據member objectsd的聲明次序,依次調用必要的default constructors。
類似這樣:
Bar::Bar(){ foo.Foo::Foo(); str = 0;}
2、帶有Default Constructor的Base Class
一個沒有任何建構函式的類派生自一個帶有default constructor的父類,那麼這個衍生類別的預設建構函式是nontrivial的。 它將調用base class的default constructor。
和上一條類似,當設計者提供多個建構函式時,編譯器會擴張現有建構函式,在最開始調用base class constructor。
3、帶有一個Virtual Function的Class
a) class聲明或繼承一個virtual function。
b)class派生自一個繼承鏈,其中有一個或多個virtual base function。
下面兩個擴張操作會在編譯期間發生:
1、一個virtual function table。裡面儲存class的virtual functions地址
2、每個class object中的vptr,儲存的是class vtbl的地址。
4、帶有一個 Virtual Base Class的Class
C++物件模型之預設建構函式