C++類的內存結構


摘自Jerry19880126

簡單類

class Base
{
    int a;
    int b;
public:
    void CommonFunction();
};

簡單類繼承

class DerivedClass: public Base
{
    int c;
public:
    void DerivedCommonFunction();
};

帶有虛函數的類

class Base
{
    int a;
    int b;
public:
    void CommonFunction();
    void virtual VirtualFunction();
};

虛函數類繼承

沒有復寫的繼承

 class DerivedClass: public Base
{
    int c;
public:
    void DerivedCommonFunction();
    void virtual VirtualFunction();
};

復寫的繼承

class DerivedClass1 : public Base
{
    int c;
public:
    void DerivedCommonFunction();
    void virtual VirtualFunction();
    void virtual VirtualFunction2();
};

多重繼承

class Base
{
    int a;
    int b;
public:
    void CommonFunction();
    void virtual VirtualFunction();
};


class DerivedClass1: public Base
{
    int c;
public:
    void DerivedCommonFunction();
    void virtual VirtualFunction();
};

class DerivedClass2 : public Base
{
    int d;
public:
    void DerivedCommonFunction();
    void virtual VirtualFunction();
};

class DerivedDerivedClass : public DerivedClass1, public DerivedClass2
{
    int e;
public:
    void DerivedDerivedCommonFunction();
    void virtual VirtualFunction();
};

內存分布從父類到子類,依次如下:
Base中有一個虛表指針

DerivedClass1繼承了Base,內存排布是先父類后子類。

DerivedClass2的情況是類似於DerivedClass1的。

DerivedDerivedClass,由外向內看,它並列地排布着繼承而來的兩個父類DerivedClass1與DerivedClass2,還有自身的成員變量e。DerivedClass1包含了它的成員變量c,以及Base,Base有一個0地址偏移的虛表指針,然后是成員變量a和b;DerivedClass2的內存排布類似於DerivedClass1,注意到DerivedClass2里面竟然也有一份Base。

這里有兩份虛表了,分別針對DerivedClass1與DerivedClass2,在&DerivedDericedClass_meta下方的數字是首地址偏移量,靠下面的虛表的那個-16表示指向這個虛表的虛指針的內存偏移,這正是DerivedClass2中的{vfptr}在DerivedDerivedClass的內存偏移。

虛繼承

class DerivedClass1: virtual public Base
{
    int c;
public:
    void DerivedCommonFunction();
    void virtual VirtualFunction();
};

class DerivedClass2 : virtual public Base
{
    int d;
public:
    void DerivedCommonFunction();
    void virtual VirtualFunction();
};

class DerivedDerivedClass :  public DerivedClass1, public DerivedClass2
{
    int e;
public:
    void DerivedDerivedCommonFunction();
    void virtual VirtualFunction();
};

Base類沒有變化

DerivedClass1就已經有變化了,原來是先排虛表指針與Base成員變量,vfptr位於0地址偏移處;但現在有兩個虛表指針了,一個是vbptr,另一個是vfptr。vbptr是這個DerivedClass1對應的虛表指針,它指向DerivedClass1的虛表vbtable,另一個vfptr是虛基類表對應的虛指針,它指向vftable。

下面列出了兩張虛表,第一張表是vbptr指向的表,8表示{vbptr}與{vfptr}的偏移;第二張表是vfptr指向的表,-8指明了這張表所對應的虛指針位於內存的偏移量。

DerivedClass2的內存分布類似於DerivedClass1,同樣會有兩個虛指針,分別指向兩張虛表(第二張是虛基類表)。

下面來仔細看一下DerivedDerivedClass的內存分布,這里面有三個虛指針了,但base卻只有一份。第一張虛表是內含DerivedClass1的,20表示它的虛指針{vbptr}離虛基表指針{vfptr}的距離,第二張虛表是內含DerivedClass2的,12表示它的虛指針{vbptr}離虛基表指針{vfptr}的距離,最后一張表是虛基表,-20指明了它對應的虛指針{vfptr}在內存中的偏移。


虛繼承的作用是減少了對基類的重復,代價是增加了虛表指針的負擔(更多的虛表指針)。

下面總結一下(當基類有虛函數時):

1. 每個類都有虛指針(vptr, virtual table pointer)和虛函數表(vtbl, virtual table); 2. 如果不是虛繼承,那么子類將父類的虛指針繼承下來,並指向自身的虛函數表(發生在對象構造時)。有多少個虛函數,虛函數表里面的項就會有多少。多重繼承時,可能存在多個的基類虛函數表與虛指針; 3. 如果是虛繼承,那么子類會有兩份虛指針,一份指向自己的虛函數表,另一份指向基類虛函數表,多重繼承時基類虛函數表與基類虛指針有且只有一份。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM