一、Default constructor
1. 對於class X ,如果沒有任何user-declared constructor,那麼編譯器生成的default constructor是無用的
2. 編譯器合成(擴張)的default constructor 是有用的4中情況
①.帶有default constructor的member class object
Member class object 的Default constructor會在合成(擴張)的default constructor調用。
②.帶有default constructor的base class
合成(擴張)的default constructor會調用base class的default constructor
③.帶有一個virtual funtion的class
合成(擴張)的default constructor會初始化類的vptr
④.帶有一個virtual base class的class
3. 誤區
①.任何class如果沒有定義default constructor,就會被合成出來。
②.編譯器合成出來的default constructor 會被明確設定class內的每一個data member的默認值。
二、Copy constructor
1. 有三種情況,會以一個object的內容作為另一個class的初值。
①.明確的以一個object的內容作為另一個class object的初值 X xx = x;
②.當object被當作參數交給某個函數時 void foo(X x)
③.當函數傳回一個class object x = foo() { return xx;}
如果定義了copy constructor則大多數情況下會被調用,否則其內部是以所謂的default memberwise initialization 手法完成,對於其中member class object是以遞歸方式施行memberwise initialization。
2. 編譯器會合成copy constructor的情況即class不表現出bitwise copy semantics
①.當class內含一個member object而後者的class聲明有一個copy constructor時(具備條件合成的)
②.當class繼承自一個base class而後者存在有一個copy constructor(被明確聲明或被合成)
③.當class聲明了一個或多個virtual funtions時
④.當class派生自一個繼承串鏈,其中有一個或多個virtual base classes時
下面對第三點做簡要說明:
我們知道編譯期間的兩個程序擴張操作(有virtual funtion存在的前提下)
I.增加一個virtual function table(vtbl),內含每一個有作用的virtual function的地址
II.將一個指向virtual function table的指針(vptr),安插在每一個class object內
從這兩點我們可以看出編譯器需要合成出一個copy constructor以求將vptr適當的初始化。
class ZooAnimal
{
public:
ZooAnimal(){}
virtual ~ZooAnimal(){}
virtual void animate(){}
virtual void draw() {}
};
class Bear : public ZooAnimal
{
public:
Bear(): b(5){memset(this, 0, sizeof(Bear));}
virtual void animate(){}
virtual void draw() {}
virtual void dance(){}//父類沒有的虛函數
};
Bear yogi;
Bear winnine = yogi;
這種情況下yogi的vptr值拷貝給winner的vptr是安全的,也就說此時兩個對象的vptr完全一樣。
但是下面這種情況
ZoonAnimal franny = yogi;
此時franny的vptr不可以被設定指向Bear class的virtual table。也就說合成出來的ZoonAnimal copy constructor會明確設定object的vptr指向ZoonAnimal class的virtual table,而不是直接從右手邊的class object將其vptr現值拷貝過來
三、成員初值列(member initialization list)
1. 為了通過編譯必須使用member initialization list的情況
① 當初始化一個reference member
② 當初始化一個const member
③ 當調用一個base class的constructor,而它擁有一組參數時
④ 當調用member class的constructor,而它擁有一組參數時
初始化順序不是有list中的項目順序而是有member聲明次序決定;編譯器會一一操作initialization list根據聲明次序在constructor內安插初始化操作,並且在任何explicit user code之前。
版權聲明:本文為博主原創文章,未經博主允許不得轉載。