1、
2、c++虛繼承下菱形繼承的物件記憶體布局依賴於編譯器。對於vs而言,虛繼承通過虛基類表和虛基類指標(vbptr)實現;對於g++而言,可能會有另一種實現方式。本文基於文章和文章中描述的實驗方法,在linux和g++編譯器環境下,測定了虛繼承菱形繼承生成物件的記憶體布局。
執行環境:
ubuntu16.04,g++5.4.0,64位
**:
#include
using
namespace
std;
class b
virtual
void f()
virtual
void bf()
};class b1 : virtual
public b
virtual
void f()
virtual
void f1()
virtual
void bf1()
};class b2 : virtual
public b
virtual
void f()
virtual
void f2()
virtual
void bf2()
};class d : public b1, public b2
virtual
void f()
virtual
void f1()
virtual
void f2()
virtual
void df()
};int main(void)
程式執行結果:d::f()
sizeof(t): 56
實驗步驟:
1、依次將**中處的vfptr偏移值+1,可測出vfptr指向的虛函式表的所有函式資訊;
2、變換處指標p的型別,改為d、b1、b2和b,重複1步驟,可測得所有的虛函式表中函式資訊。
結論:上述實驗中,d物件記憶體模型為:
經過記憶體補齊計算,在64位環境中d物件記憶體位56byte,與上述記憶體布局吻合。
1、派生類物件建立過程中,首先建立直接基類(非virtual繼承)的物件模型。直接基類物件建立過程可不考慮派生類因素,按照其自身的建立方法建立,依次向上。
2、建立虛基類時候,同樣不用考慮派生類,按照自身原本的方法建立。此部分記憶體放在派生類物件記憶體最後。
3、建立派生類,類中的虛函式更新到基類的虛函式表中。新新增的部分放在第乙個直接基類虛函式表最後,如上述實驗。
4、上述實驗中,b1* p = &d、b2* p = &d和b* p = &d不相同,但各自指向各自部分的虛函式表首位址。b1* p = &d和d* p = &d相同。
**1:
#include
using
namespace
std;
class a ;
class b : virtual
public a
};int main()
不同環境下有不同結果。
測試建構函式執行順序
**:
#include
using namespace std;
class test
test(int m)
};class a
private:
test t1;
};class b
private:
test t2;
};class c :virtual
public a, public b
private:
test t3;
};int main()
**:
#include
using
namespace
std;
class a
};class b :virtual
public a
virtual
void fun2()
};int main()
結果:
1、linux,64位,g++:
32 2、windows,64位
40結論:驗證了之前的假設,因為windows處理虛繼承,採用虛基類表方式(vbptr),而linux無論類中有沒有虛函式,只要虛繼承,都會建立乙個虛函式表。
其實有更好的方式來直觀了解windows和linux中類物件的記憶體布局,各自系統中有相關方法,下次總結。
C 菱形繼承
在c 繼承體系中,有一類問題是永遠跑不掉的即菱形繼承問題。此類問題又被稱作鑽石繼承問題,只是一種較差的設計結構,剛好看到這個問題,特此總結一下。先來看一下菱形繼承的基本結構 a和b從基類base中繼承,而d多重繼承於a,b。那就意味著d中會有base中的兩個拷貝。因為成員函式不體現在類的記憶體大小上...
c 菱形繼承
單繼承 乙個子類只有乙個父類時稱為單繼承 多繼承 乙個子類有兩個或者兩個以上時這個繼承關係為多繼承 菱形繼承是多繼承的一種特殊情況 在繼承中子類會繼承父類的所有的成員,可以看出菱形繼承有資料冗餘和二義性的問題。assistant中會有person的兩份資料。可以從上面看出來我們的assistant中...
C 菱形繼承
1 多重繼承的問題 在c 類的繼承中會遇到這樣乙個問題,乙個派生類有兩個或者兩個以上的基類,如同下面這種繼承情況 類c繼承了類a和類b,但是類a和類b裡面有著相同的成員變數,那麼類c在使用這個成員變數的時候就會出現二義性的問題,需要通過域成員運算子進行區分 class a a void displa...