深度探索C++對象模型筆記(五)

Semantics of Construction,Destruction,and copy

考慮如下abstract base class聲明:
class Abstract_base
{
public:
virtual ~Abstract_base() = 0;
virtual void interface() const = 0;
virtual const char* mumble() const
{
return _mumble;
}
protected:
char* _mumble;
};
雖然這個class被設計爲一個抽象的base class(其中有純虛函數,不可能擁有實體),但它仍然需要一個明確的構造函數以初始化其data member _mumble。

純虛擬函數的存在

我們可以靜態調用一個純虛函數(如Abstract_base::interface())。

關於純虛析構函數,因爲每一個派生類的析構函數會被編譯器擴展,以靜態的方式調用每一個虛基類以及上一層基類的析構函數,因此只要缺乏任何一個基類析構函數的定義,就會導致鏈接失敗。一個比較好的方案是,不要將虛析構函數聲明爲純虛。

虛擬規格的存在

如果將Abstract_base::mumble()設計爲一個虛函數,那將是一個糟糕的設計。因爲它幾乎不會被後繼派生類改寫。一般而言,把所有的成員函數聲明爲虛函數,然後由編譯器的優化操作把非必要的virtual invocation去除,並不是好的設計觀念。

虛擬規則中const的存在

決定一個virtual function是否需要const,是一件瑣屑的事情。當你面對一個abstract base class時,卻不容易做決定,聲明一個函數爲const,然後才發現其派生類必須修改一個data member。簡單的做法是,不用const就是了。

重新考慮class的聲明

class Abstract_base
{
public:
virtual ~Abstract_base();
virtual void interface() const = 0;
const char* mumble() const
{
return _mumble;
}
protected:
Abstract_base(char *pc = 0);//新增一個帶唯一參數的構造函數
char* _mumble;
};

1、“無繼承”情況下的對象構造

對比無繼承情況下Point結構體和class(添加默認構造函數)trivial 類函數(構造,析構,拷貝)的情況,可複習此前的筆記即可。

2、繼承體系下的對象構造

(略)

vptr初始化

如果在集成體系中每一個constructor內調用一個virtual函數,那麼每一次調用的都是什麼函數呢?C++規則告訴我們,在Point3d constructor中調用的size()(virtual函數),必須爲Point3d::size(),即由構造函數(析構函數)中的對象調用一個virtual function,其函數實體應該是在此class中有作用的那個。由於構造順序是:由根源末端(bottom up),由內而外,base class constructor執行時,derived實體還沒有構造出來。因此如果調用操作必須在constructor和destructor中直接調用,那麼將每一個調用操作以靜態方式決議之,千萬不要用到虛擬機制。另一種方法是在constructor和destructor內設置一個標誌,以標誌確定是否以靜態調用方式進行。

vptr在constructor中應該在何時被初始化,我們有三種選擇:

  1. 在任何操作之前
  2. 在base class constructors調用操作之後,但是在程序員的代碼或者是member initialization list中所列的members被初始化之前
  3. 在每一件事情發生之後
答案是2。

3、Object copy Semantics

當我們以一個class object指定給另一個class object時,我們有三種選擇:

  1. 什麼都不做,因此得以實施默認行爲
  2. 提供一個explicit copy assignment operator
  3. 明確的拒絕把一個class object指定給另一個class object
如果選擇第三點,那麼只要將copy assignment operator聲明爲private,並且不提供定義即可。
餘下部分內容前面筆記有記錄,主要是在什麼情況在位拷貝會無效,虛擬繼承部分不做記錄
專家建議:不要在任何virtual base class 中聲明數據

4、Semantics of Destruction

若class未定義destructor,那麼只有在class內的member object或者是base class擁有destructor的情況下,編譯器纔會合成出一個否則就算class擁有virtual function,也不會合成。
爲了決定class是否需要程序層面的destructor或是constructor,想想一個class的生命在哪裏結束或開始,需要什麼操作才能保證對象的完整?這也是constructor和destructor什麼時候起作用的關鍵。例如:對象在使用前必須初始化爲某些特定值,這時候需要一個constructor,當我們明確的delete一個對象時,如果沒有理由先將其內容清除乾淨,也不需要歸還任何資源,那麼不一定需要一個destructor

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章