C 繼承與Class 記憶體模型

2021-08-03 17:58:55 字數 3500 閱讀 9353

c++類主要包括屬性和操作兩類,在物件模型中即乙個物件例項中占用記憶體的只是class的屬性部分,也就是資料成員部分,本文旨在剖析c++物件模型中在有繼承情形下類物件的記憶體布局,主要分4種情況討論:單一繼承沒有多型、單一繼承有多型、多重繼承、虛擬繼承。

所謂單一繼承沒有多型,也就是class b繼承於(public繼承)class a,而且class a沒有虛函式。在這種情況下,class b的物件記憶體中就會包含乙個父類部分,其整個記憶體模型有父類部分和本身部分組成。如有兩個類class point2d和class point3d定義如下:

class point2d

;class point3d : public point3d

;

可以看出這是乙個單一繼承模型,即class point2d繼承於class point3d,由於派生類記憶體模型包含基本部分和自身兩個部分,所以point2d和point3d物件的記憶體模型分別為:

注意,上圖中右邊是point3d的物件模型,上半部分是基類部分,下半部分是自身部分,這種上下結構基本是繼承模型(不管是單繼承還是多繼承)的乙個標準結構,一般都是基類部分在上,自身部分在下。

所謂單一繼承帶有多型,也就是在上面point2d和point3d繼承體系中基類class point2d有虛函式,這是point2d和point3d的定義如下:

class point2d

;class point3d : public point3d

;

由於class point2d中帶有虛函式,也就是對point2d來說具有多型,因此編譯器要做一些額外的工作,這些額外的工作包括:(1)編譯器為point2d生成乙個虛函式表(virtual function table,簡稱為vft),vtf中儲存的是類中虛函式的位址;(2)編譯器在point2d記憶體模型中插入乙個指標物件,即虛函式表指標,指向虛函式表;(3)編譯器要在class的預設建構函式和析構函式中增加一些**,用來處理新增加的虛函式表指標,使它指向每個class對應的虛函式表

(注意,在單一繼承系統中,每個層次的class都只有乙個虛函式表和虛函式表指標,而對於多重繼承系統中的派生類就有多個,後面會說明)。此時,point2d和point3d的物件模型為:

上圖中,左右分別為point2d和point3d物件記憶體模型,但請注意,在兩個模型中的虛函式表指標都是int vp2d;而且int vp2d在point3d模型中是屬於基類部分,這裡有兩層意思:(1)在單一繼承中,派生類的虛函式表指標是從基類繼承而來的(當然,這只是在基類由虛函式的情況下,如果基類沒有虛函式,而派生類有虛函式,那就不用繼承);(2)繼承而來的虛函式表指標在派生類的建構函式中需要重新賦值,指向派生類自己的虛函式表,因為派生類除了覆蓋基類的虛函式外,還有可能擁有自己的虛函式。

針對上述第(2)層意思作進一步說明,如果說point3d確實除了覆蓋基類point2d的虛函式外,還自己定義了乙個或者多個虛函式的情況,具體分析兩個class的虛函式表構成,如將point2d和point3d的定義修改如下:

class point2d

;class point3d : public point3d

;

在上述定義中,我們只在point3d中增加了乙個虛函式,則point2d和point3d的虛函式表構成分別為:

上圖關於point2d和point3d的虛函式表的構成可知新增加的虛函式virtual void show()是跟在基類的虛函式後面的。

其實在理解了單一繼承的情況下,理解多重繼承還是比較好理解的,無非就是在派生類的記憶體結構中多了幾個基類部分,也就是n個基類部分+1個自身部分,這裡的n就是派生列表中基類的個數,如以下這乙個多重繼承體系:

上述繼承體系表示為:class vertex2d : public point2d, public vertex,上述三個類的定義如下:

class point2d

;class vertex

;class vertex2d : public point2d, public vertex

;

根據上述class定義,point2d有虛函式介面,vertex有虛函式介面,vertex2d有覆蓋和新增虛函式,則各class的記憶體模型如下:

上圖中,class vertex有兩個基類部分,而且分別從兩個基類繼承了兩個虛函式表指標,而至於每個虛函式表指標所指虛函式表的結構這裡不進行詳細介紹,後期會專門更新一篇文章進行闡述。

理解虛擬繼承,最核心的乙個概念就是需要記住:從虛擬基類派生的派生類記憶體模型構成由不變部分和共享部分組成,而這個共享部分指的就是虛擬基類,不變部分又包括直接基類部分和自身部分。之所以有這樣乙個結構,是因為虛擬繼承一般都是在至少有三層繼承的情況下才能發揮實際作用,當然,比如剛剛介紹的單一兩層繼承體系結構也可以使用虛擬繼承,只是沒有什麼實際意義。虛擬繼承主要是為了解決多路繼承情況下的成員重複的問題。(博友可以查閱其他專門介紹虛擬繼承的文章進行進一步的了解)

如果有以下虛擬繼承結構:

其中class point2d是虛擬基類,具體繼承關係為:

class vertex  : virtual public point2d

class point3d  : virtual public point2d

class vertex3d  : public vertex, public point3d

各個class定義如下:

class point2d

;class vertex : virtual public point2d

;class point3d : virtual public point2d

;class vertex3d : public point3d, public vertex

;

根據以上定義,以及上面3中情況的分析,我們可以推斷出class vertex3d的記憶體模型中應該是擁有3個虛函式表指標,分別繼承於point3d和vertex兩個類,另外乙個虛函式表指標是來自於共享部分,即point 2d的虛函式表指標。

class與class的繼承

1 class point 6tostring 9 10var foo new point 2,3 11console.log foo.x 12 es6類完全可以看作建構函式的另一種寫法 13 type of function 14 point point.prototype.constructor...

C 繼承模型的記憶體布局

對於多繼承情況 考慮示例 structbase1 structbase2 structderived base1,base2 有如下記憶體布局 首先出現的是派生類derived類的虛表指標vptr 一直以來vptr都被國人翻譯為虛函式表指標 但是vtbl英文原文是virtual table並非vir...

C 中class 類 與繼承白話學習筆記

class drink 別忘了最後要加乙個分號 當我們需要描述一杯飲料的時候,我們可以如下使用drink類 drink a 新建乙個飲料物件 printf the volume of the drink is lf n a.volume 在c 中,作用域除了public,private還有prote...