C++ 多重继承之内存存储
C++ 之多重繼承
1. C++中class與struct。
在C++里面,class與struct沒有本質(zhì)的區(qū)別,只是class的默認權(quán)限是private,而struct則是public。這個概念也揭示了一點:class和struct在內(nèi)部存儲結(jié)構(gòu)上是一致的。所以我們可以利用這一點來探討class的實現(xiàn)原理。我們可以將class轉(zhuǎn)換成對應(yīng)的struct對象,通過struct的簡單性來展示class的內(nèi)存存儲結(jié)構(gòu)。
2. 關(guān)于class的基本內(nèi)存結(jié)構(gòu)
class包括成員變量和成員函數(shù)。對于成員變量,其結(jié)構(gòu)和struct的結(jié)構(gòu)是一致的,即按照聲明的順序,安排每個成員的內(nèi)存位置。對于成員函數(shù),如果是非虛函數(shù)(包括普通函數(shù)和靜態(tài)函數(shù)),他們實際上同其他函數(shù)沒有區(qū)別。對于非靜態(tài)非虛函數(shù),默認隱藏了this參數(shù)。當編譯時,編譯器將函數(shù)地址直接編譯進去。因此,這類函數(shù)沒有動態(tài)能力。對于虛函數(shù),其函數(shù)地址將存在類this指針關(guān)聯(lián)的虛函數(shù)內(nèi)(參見上一篇文章),在運行時,從虛函數(shù)表內(nèi)取得地址后再調(diào)用。
這樣一個不帶虛函數(shù)的類的內(nèi)存結(jié)構(gòu),等同與一個類似的struct,而帶虛函數(shù)的類的內(nèi)存結(jié)構(gòu),等同于一個帶有虛函數(shù)指針的struct。我用偽代碼可以清晰的表示出來:
[cpp]?view plaincopy
class ClassAWithVirtual { int a; float b; void* c; virtual ~ClassAWithVirtual();};//等同于struct StructAWithVirtual { VTable *vtable; //包括虛函數(shù)表的vtable int a; float b; void *c;};
單線繼承是很簡單也很容易理解的一種繼承方式。如果有class B繼承自class A。那么,在class B的低地址部分,是class A的成員空間。這樣class B可以直接轉(zhuǎn)換為class A。
如果class A有虛函數(shù),那么class B必須也有虛函數(shù)表。那么,如果class A沒有虛函數(shù),而class B卻有虛函數(shù),那么這個時候的內(nèi)存分布應(yīng)該是什么樣呢?class B還能否直接轉(zhuǎn)換為class A呢?
[cpp]?view plaincopy
在G++ 4.6 ubuntu 10.04下,輸出的結(jié)果是
[cpp]?view plaincopy
3. 不帶虛函數(shù)的C++的多重繼承類的內(nèi)存分布
一般情況下,如果一個類繼承自兩個類以上,那么,它的內(nèi)存分布會像壘磚頭那樣一層一層的添加上去。比如
[cpp]?view plaincopy
輸出結(jié)果是
[cpp]?view plaincopy
[cpp]?view plaincopy
那么,再考慮一種情況,如果是這樣一種繼承方式:
? ? ? ? ? ? ? ? ? ? ? ? ?A
? ? ? ? ? ? ? ? ? ? ? / ? ? \ ? ? ??
? ? ? ? ? ? ? ? ? ? B ? ? ?C
? ? ? ? ? ? ? ? ? ? ?\ ? ? ?/
? ? ? ? ? ? ? ? ? ? ? ?D
那么A的成員在D內(nèi)部是一份還是兩份?
[cpp]?view plaincopy
[cpp]?view plaincopy
結(jié)合輸出結(jié)果,class D內(nèi)部仍然等同于
[cpp]?view plaincopy
?
由此可見,不管繼承層次有多深,C++總是按照這種壘磚頭的方式疊加。如果有祖先類內(nèi)部有重復(fù)包含,那么,C++也會重復(fù)包含相同的內(nèi)容。
這也提醒我們,多重繼承不能太復(fù)雜,否則就很難搞清楚其結(jié)構(gòu)關(guān)系了。
4. 帶虛函數(shù)的類的多重繼承的內(nèi)存分布
帶虛函數(shù)的情況下,情況會變得非常復(fù)雜。首先,對于最簡單的一種繼承方式
? ? ? ? ? ? ? ? ? ? ? ? ?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虛, 按照默認的規(guī)則,A的內(nèi)存會被安排在偏移0處。這個時候,A的虛函數(shù)表也就是C的虛函數(shù)表。
如果只有B虛,因為B的內(nèi)存會被安排在A之后,那么,B的虛函數(shù)表應(yīng)該在B所在位置,C沒有虛函數(shù)表。
4.2 A B 不虛,C虛
這種情況下,虛函數(shù)表應(yīng)該在偏移0處,然后才是A和B的內(nèi)存結(jié)構(gòu)。我們來驗證一下:
總結(jié)
以上是生活随笔為你收集整理的C++ 多重继承之内存存储的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python植物大战僵尸源码分享
- 下一篇: C++中string.find()的误用