深入探索C++物件模型-第五章-構造、析構、拷貝語意學

來源:互聯網
上載者:User

繼續整理第五章的內容,關於累的三個重要函數:建構函式,解構函式,拷貝建構函式。註:以下部分圖片來自原書

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)以防止虛基類多次構造。











相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.