繼續整理第五章的內容,關於累的三個重要函數:建構函式,解構函式,拷貝建構函式。註:以下部分圖片來自原書
1. 無繼承情況下的物件建構。
當類中存在虛函數時,編譯器會對該類產生膨脹作用, 例如如下類:
class Point {public: Point(float x = 0.0, float y = 0.0) : _x(x), _y(y){} virtual float z();protected: float _x, _y;};
a. 我們所定義的建構函式中,會被附加一些代碼,一邊初始化虛表指標(vptr),這些代碼會安插在任何基類建構函式的調用之後,但必須在任何使用者供應的代碼之前,一種可能的上述Point類的建構函式擴充:
Point* Point::Point (Point* this, float x, float y) : _x(x), _y(y){ //設定虛表指標 this->__vptr_Point = __vtbl__Point; //擴充成員變數初始化列表 this->_x = x; this->_y = y; //傳回this對象 return this;}
b. 合成一個拷貝構造和拷貝賦值函數,這兩個函數是重要的,會被調用的,用來在這兩個函數被調用時,設定虛表指標等操作,可能的擴充結果:
//copy constructorinline Point* Point::Point (Point* this, const Point& rhs){ //設定虛表指標 this->__vptr_Point = __vtbl__Point; //資料成員拷貝 //傳回this對象 return this;}
2. 繼承情況下的物件建構。
當我們定義一個類對象時:T object,建構函式可能會發生擴充:
a. 初始化列表中資料成員初始化操作會放入建構函式本身,注意是以資料成員在類中的聲明順序,而非在初始化類表中的順序。
b. 如果有某一個資料成員未出現在初始化列表中,但是他有預設建構函式,則該預設建構函式會被調用。
c. 在那之前,如果如果類該對象有虛表指標,它(們)會設定初值,指向適當的虛表(們)。
d. 在那之前,所有基類建構函式會被調用,按照它們在子類中的繼承順序:
i. 如果基類在初始化列表中,任何明確指定的參數都需要傳遞進去。
ii. 如果基類沒有列於初始化列表,那麼會調用可能存在的預設建構函式。
iii. 如果基類是多重繼承下的第二個或者後繼,那麼此時子類的this指標需要被調整,以指向該基類部分(subobject)。
e. 在那之前,所有虛基類的建構函式必須被調用, 從左至右,從最深到最淺。
i. 如果基類在初始化列表中,任何明確指定的參數都需要傳遞進去,如果沒有,會調用可能存在的預設建構函式。
ii. 類中每一個虛基類子物件的位移(offset)必須在執行期可被存取。
iii. 如果類對象是最底層的(most-derived),其建構函式可能會被調用,某些支援這個行為的機制會被放入(下文提到的__most_derived)。
繼續以Point為例,進行一下擴充,並聲明Line類:
第二個建構函式會被擴充為:
解構函式會被擴充為:
虛擬繼承情況下,子類建構函式的擴充有些不一樣,考慮如下類以及其繼承體系:
由於虛基類在子類中只有一份,所以虛基類Point的建構函式只能被調用一次,例如,在執行個體化Point3d或者Vertex對象時,作為二者直接基類的Point的建構函式需要調用,但是在定義Vertex3d對象時,會調用Point3d和Vertex的建構函式,此時二者的構造不應該調用Point的建構函式,因為Point已經在Vertex3d建構函式中調用過了,為了保證虛基類的唯一性,不允許再調用,也就是只有最下層的子類建構函式中需要調用虛基類的建構函式,Point3d的建構函式以及Vertex3d的建構函式的可能擴充如下,注意紅框中的內容:
在Vertex3d建構函式中,當調用其父類Point3d以及Vertex的建構函式時,__most_derived參數會設定為false,已壓制而這對於Point的再次初始化:
3. 關於虛表指標的初始化在子類建構函式中的情況。
a. 子類建構函式中,所有虛基類以及基類的建構函式會被調用。
b. 接著是對象的虛表指標被初始化,指向相關的虛表。
c. 在建構函式內展開可能存在的資料成員初始化列表,由於此時可能有虛函數調用,所以該步必須在虛表指標初始化妥當之後。
d. 最後,指向我們碼農提供的代碼。
例如,之前例子中的PVertex類的某個建構函式如下:
可能會被擴充成為,下圖貌似有一點遺漏,this->Vertex3d::Vertex3d(x, y, z)應該是:this->Vertex3d::Vertex3d(false, x, y, z)以防止虛基類多次構造。