1. 程式人生 > 其它 >C++菱形繼承記憶體分佈和解決方案分析

C++菱形繼承記憶體分佈和解決方案分析

struct A
{
    int a=1;
};
struct B:A
{
    int b=2;
};
struct C:A
{
    int c=3;
};
struct D:B,C
{
    int d=4;
};
int main()
{
    D d;
//d.a = 1; std::cout
<< sizeof(d) << endl;//20 }

菱形繼承:基類有兩個子類,有一個類繼承了這兩個基類的子類,就形成了菱形繼承。這樣繼承會導致d類繼承過來的欄位冗餘,B類會繼承父類a欄位構造後會擁有ab欄位,C類會擁有ac欄位,D類繼承bc類會有abacd五個欄位。當我們給a欄位賦值時,將會報a不明確的錯誤,因為d物件有兩個a欄位。

分析完畢接下來看彙編:

進入D類的建構函式,進入構造會傳入該類的首地址,根據首地址查詢到該類在記憶體的地址,都是cc。

構造自身前會先call的是B類的構造。

call完A的構造B類的記憶體地址已經改變,1已經被賦值進記憶體。

在構造裡B類構造裡把b欄位初始化為

初始化構造後d物件的記憶體分佈就是有12134這四個欄位。

解決方案:虛繼承

struct A
{
    int a=1;
};
struct B: virtual A
{
    int b=2;
};
struct C:virtual A
{
    int c=3;
};
struct D:B,C
{
    int
d=4; }; int main() { D d; d.a = 1; std::cout << sizeof(d) << endl;//48 }

記憶體地址分佈:

會包含兩張虛表,啷個父類欄位,一個基類欄位,一個自身欄位,虛表裡存了28和18。我們計算一下第一張虛表和基類欄位a的地址差和第二張虛表與欄位a的地址差,會發現剛好是28和18,所以虛表裡存的數值是基類欄位和虛表的記憶體差,可以根據值尋找到共享欄位的記憶體地址。