給出這樣的重複繼承:
(一)、直接繼承,沒有虛函式存在時,書寫如下:
class ca
;class cb:public ca
;class cc:public ca
;class cd:public cb,public: cc
;
檢視記憶體布局如下:
由於b和c都繼承了a,所以在d中重複出現了a中的成員變數,所以當試圖訪問間接基類中的成員變數時,務必要加上作用域。
當把類ca、cb、cc、cd中的函式都寫成虛函式時,依舊還是重複出現,如下圖:
(二)、虛繼承
書寫**如下:(將繼承關係改為虛繼承)
class ca
virtual void a()
virtual void aa()
virtual void aaa()
public:
int ma;
};class cb:virtual public ca
virtual void a()
virtual void bb()
virtual void bbb()
protected:
int mb;
};class cc:virtual public ca
virtual void a()
virtual void cc()
virtual void ccc()
protected:
int mc;
};class cd:public cb,public cc
virtual void a()
virtual void bb()
virtual void ccc()
virtual void d()
protected:
int md;
};
對於虛繼承,可以避免重複繼承的作用,列印其記憶體布局看看情況:
可以看到在虛繼承下,前面所說的出現兩次的成員變數和成員函式出現了一次,且都放在了記憶體布局中的最後面,那怎麼找到呢?就是從圖中看到的vbptr指標,它指向vbtable,vbtable中記錄了兩行數字,據分析,可以做出總結:
根據以上記憶體布局,做出列印:
typedef void (*function)(void);//函式指標
int main()
{ cd d(40);
long** pd=(long**)(&d);//將物件d的位址強轉成為二級指標。
現在就可以畫出記憶體布局:
總結:1、當出現重複繼承時(像這種菱形繼承),會重複出現間接基類的資料,一般為了避免重複出現,因此採用虛繼承(虛擬繼承)。
2、在虛擬繼承下,編譯器將重複出現的資料放在了這個記憶體布局的最後邊(當然有vfptr時還是依據vfptr優先順序高放),並且為了標記它,在每個直接父類的作用域下有了vbptr指標,用來指向存放重複出現資料相對的偏移的vbtable。
3、在檢視記憶體布局時,看到了下標七号存放著乙個0,也就是上面標記的vtordisp for vbase ca,為什麼是0?不知道為什麼,也沒查出結果,我猜想是為了做區分吧。
論c 中物件的記憶體布局
物件的記憶體布局就是計算物件所占用的記憶體大小,物件的大小只包含資料成員,類成員函式是執行 不屬於物件的資料成員。在不討論類的繼承,以及虛函式的時候。乙個物件的大小的計算公式一般為 物件的大小 sizeof 資料成員1 sizeof 資料成員2 sizeof 資料成員n 但是,即便在這種情況下,仍然...
C 物件的記憶體布局
一篇寫的比較好的部落格 這篇文章中主要想說以下幾個問題 1 如何通過物件獲得虛函式表中虛函式的位址 2 分幾種情況討論記憶體布局 1 單一繼承 2 多重繼承 3 重複繼承 4 鑽石虛擬繼承 為了解決重複繼承中出現問題而產生的虛擬繼承 1 虛函式主要是通過一張虛函式的位址表來實現的,簡稱v table...
C 物件的記憶體布局
記憶體布局是屬於較深層次的知識,很多問題往深了講都是不清楚記憶體布局的原理。最近讀到一本書,裡面講了一部分c 物件的記憶體布局,讓我對很多以前的問題都豁然開朗了。書上篇幅較大,我加上自己的理解總結了下。分為三部分 簡單物件,單繼承,多繼承 非靜態成員變數和虛函式是決定類大小的唯一兩個因素 非靜態成員...