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=12b=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實際上就是乙個虛函式列...