C 多重繼承之記憶體儲存

2021-08-03 09:39:54 字數 3473 閱讀 5172

c++ 之多重繼承

1. c++中class與struct。

在c++裡面,class與struct沒有本質的區別,只是class的預設許可權是private,而struct則是public。這個概念也揭示了一點:class和struct在內部儲存結構上是一致的。所以我們可以利用這一點來**class的實現原理。我們可以將class轉換成對應的struct物件,通過struct的簡單性來展示class的記憶體儲存結構。

2. 關於class的基本記憶體結構

這樣乙個不帶虛函式的類的記憶體結構,等同與乙個類似的struct,而帶虛函式的類的記憶體結構,等同於乙個帶有虛函式指標的struct。我用偽**可以清晰的表示出來:

[cpp]view plain

copy

class

classa ;  

//等同於

struct

structa ;  

//帶虛函式的類

offset a::a=0, offset b::a=8, offset b::b=12

b=0x7fffad613130, pa=0x7fffad613138  

class classawithvirtual ;//等同於struct structawithvirtual ;

3. class的單線繼承

單線繼承是很簡單也很容易理解的一種繼承方式。如果有class b繼承自class a。那麼,在class b的低位址部分,是class a的成員空間。這樣class b可以直接轉換為class a。

如果class a有虛函式,那麼class b必須也有虛函式表。那麼,如果class a沒有虛函式,而class b卻有虛函式,那麼這個時候的記憶體分布應該是什麼樣呢?class b還能否直接轉換為class a呢?

[cpp]view plain

copy

#include 

#include 

#define offset(x,m) (offsetof(x, m))

class

a ;  

class

b : 

public

a  };  

intmain()   

在g++ 4.6 ubuntu 10.04下,輸出的結果是

[cpp]view plain

copy

offset a::a=0, offset b::a=8, offset b::b=12  

b=0x7fffad613130, pa=0x7fffad613138  

很明顯的可以看到,當b有虛函式時,b必須在記憶體的開始處新增乙個8位元組(64位系統)的虛函式表指標。這個時候,在class b內,a的成員變數不能從偏移為0的位置開始了。

3. 不帶虛函式的c++的多重繼承類的記憶體分布

一般情況下,如果乙個類繼承自兩個類以上,那麼,它的記憶體分布會像壘磚頭那樣一層一層的新增上去。比如

[cpp]view plain

copy

#include 

#include 

class

a ;  

class

b ;  

class

c : 

public

a, public

b;  

intmain() ;  

輸出結果是

[cpp]view plain

copy

offset: c::a=0, c::b=4, c::c=8  

c=0x7fffc90bbab0, pa=0x7fffc90bbab0, pb=0x7fffc90bbab4  

這個與預想的很相似,它的等價結構是

[cpp]view plain

copy

struct

c ;  

的確像磚頭一樣,先放a,在放b,最後c的成員放上去。

那麼,再考慮一種情況,如果是這樣一種繼承方式:

a/     \       

b      c

\      /

d那麼a的成員在d內部是乙份還是兩份?

[cpp]view plain

copy

#include 

#include 

class

a ;  

class

b : 

public

a;  

class

c : 

public

a ;  

class

d : 

public

b, public

c ;  

intmain() ;  

先看一下輸出結果:

[cpp]view plain

copy

offset: d::a=0, d::b=4, d::c=12, d::d  

d=0x7fffad730f30, pa_b=0x7fffad730f30, pa_c=0x7fffad730f38, pb=0x7fffad730f30, pc=0x7fffad730f38, d.b::a=0x7fffad730f30, d.c::a=0x7fffad730f38  

事實上,如果我直接寫b.a是錯誤的,因為編譯器不知到應該選擇那個a。同樣的,如果寫a *pa = &d也是錯誤的。

結合輸出結果,class d內部仍然等同於

[cpp]view plain

copy

struct

d ;  

而且存在兩份a,這兩份a分別包含在b和c內部。在使用時,必須正確指出是那個。

由此可見,不管繼承層次有多深,c++總是按照這種壘磚頭的方式疊加。如果有祖先類內部有重複包含,那麼,c++也會重複包含相同的內容。

這也提醒我們,多重繼承不能太複雜,否則就很難搞清楚其結構關係了。

4. 帶虛函式的類的多重繼承的記憶體分布

帶虛函式的情況下,情況會變得非常複雜。首先,對於最簡單的一種繼承方式

a      b

\   /

c我們需要分好幾種情況來考慮:

1、a b虛 c非虛

2、a b 非虛,c虛

3、a b 其中乙個虛,c虛

4、a b c 都虛

4.1 a b 虛 c非虛

如果只有a虛, 按照預設的規則,a的記憶體會被安排在偏移0處。這個時候,a的虛函式表也就是c的虛函式表。

如果只有b虛,因為b的記憶體會被安排在a之後,那麼,b的虛函式表應該在b所在位置,c沒有虛函式表。

4.2 a b 不虛,c虛

這種情況下,虛函式表應該在偏移0處,然後才是a和b的記憶體結構。我們來驗證一下:

C 物件之記憶體(無繼承)

大多數情況下,非靜態成員變數在類中的宣告順序就是它們在記憶體中的排列順序。但是成員之間可能會被插入一些位元組,用於調整例項大小 存放某些指標等用途。下面深入看一下各種情況。概念介紹 access section包括public,private和protected三種段落,如果乙個類的定義中有2個pu...

多重繼承 C 中的多重繼承

多重繼承是c 的一項功能,其中乙個類可以從多個類繼承。繼承類的建構函式以它們繼承的相同順序被呼叫。例如,在以下程式中,在a的建構函式之前呼叫b的建構函式。include using namespace std class a class b class c public b,public a not...

c 多重繼承

其實想寫這篇文章,是因為突然在整理論壇上的帖子的時候,突然發現乙個人問我如何才能在c 中實現多重繼承,當時我答的很隱晦,因此這裡我想補充說明一下.首先,我要說明一下,c 中是沒有類的多重繼承這個概念.要使用多重繼承必須要通過介面inte ce來完成.可是大家都知道inte ce實際上就是乙個虛函式列...