虛繼承下類的大小

文章摘自  https://www.cnblogs.com/yvictoryr/p/3773733.html  ,紅色字體爲我認爲原博客錯誤的地方。

 

虛繼承是爲了解決多重繼承中的問題而出現的。要理解虛繼承的實現機制。

首先看一般繼承:

複製代碼

class A
{
    char k[3];
public:
    virtual void aa()
    {

    };
};
class B:public  A
{
    char j[3];
public:
    virtual void bb()
    {
        
    };
};
class C:public  B
{
    char i[3];
public:
    virtual void cc()
    {
        
    };
};
int main()
{
    cout<<sizeof(A)<<endl;
    cout<<sizeof(B)<<endl;
    cout<<sizeof(C)<<endl;  
    return 0;
}

複製代碼

得到的答案是:8 12 16

分析如下:

1、  對於類A,有一個虛函數,需要一個虛函數表vtbl來記錄函數的入口地址,每個地址一個虛指針,指針的大小爲4,類中還有一個成員變量char k[3],則根據數據對齊原則,可以得到sizeof(A)的大小爲8;

2、   對於類B,也有一個虛函數,需要一個虛函數表vtbl來記錄函數的入口地址,每個地址一個虛指針,指針的大小爲4,類中還有一個成員變量j[3],但是類B是繼承自類A的,是一般繼承,不是虛繼承,所以可以得到sizeof(B)的大小爲:  4(指向虛函數的虛指針)+4(自己的數據成員)+4(父類A的數據成員)=12;

3、  對於類C,也有一個虛函數,需要一個虛函數表vtbl來記錄函數的入口地址,每個地址一個虛指針,指針的大小爲4,類中還有一個成員變量i[3],同樣的,類C是繼承自類B的,是一般繼承,不是虛繼承,所以可以得到sizeof(C)的大小爲4(指向虛函數的虛指針)+4(自己的數據成員)+8(父類的數據成員)=16;

以上表格的虛函數指針應該位於每個類的起始地址,而不是最後。

   

再來看一下虛繼承的情況:

複製代碼

class A
{
    char k[3];
public:
    virtual void aa()
    {

    };
};
class B:public virtual A
{
    char j[3];
public:
    virtual void bb()
    {
        
    };
};
class C:public virtual B
{
    char i[3];
public:
    virtual void cc()
    {
        
    };
};
int main()
{    
    cout<<sizeof(A)<<endl;    
    cout<<sizeof(B)<<endl;
    cout<<sizeof(C)<<endl;    
    return 0;
}

複製代碼

得到的答案是:8 20 32

分析如下:

1、對於類A,有一個虛函數,需要一個虛函數表vtbl來記錄函數的入口地址,每個地址一個虛指針,指針的大小爲4,類中還有一個成員變量k[3],則根據數據對齊原則,可以得到sizeof(A)的大小爲8;

2、對於類B,也有一個虛函數,需要一個虛函數表vtbl來記錄函數的入口地址,每個地址一個虛指針,指針的大小爲4,類中還有一個成員變量j[3],但是類B是繼承自類A的,而且是虛繼承,虛繼承的實現是通過一個虛基類指針列表,比如vptr_B_A指向虛基類,同時還包含了父類的所有內容,所以可以得到sizeof(B)的大小爲:4(指向自己虛函數的虛指針)+4(自己的數據成員)+4(指向虛基類的指針vptr_B_A)+8(父類A的內容大小)=20;

3、對於類C,也有一個虛函數,需要一個虛函數表vtbl來記錄函數的入口地址,每個地址一個虛指針,指針的大小爲4,類中還有一個成員變量i[3],同樣的,類C是繼承自類B的,而且是虛繼承,虛繼承的實現是通過一個虛基類指針列表,比如vptr_C_B指向虛基類,同時還包含了父類的所有內容,所以可以得到sizeof(C)的大小爲:4(指向自己虛函數的虛指針)+4(自己的數據成員)+4(指向虛基類的指針(vptr_C_B)+20(父類B的內容大小)=32;

複製代碼

class A
{
    char k[3];
public:
    virtual void aa()
    {

    };
};
class B:public virtual A
{
    char j[3];
public:
    virtual void bb()
    {
        
    };
};
class C:public virtual A
{
    char i[3];
public:
    virtual void cc()
    {
        
    };
};
class D: public B,public C
{
    char n[3];
    public:
        virtual void dd()
        {
        
         };
};
int main()
{    
    cout<<sizeof(A)<<endl;    
    cout<<sizeof(B)<<endl;
    cout<<sizeof(C)<<endl; 
    cout<<sizeof(D)<<endl;   
    return 0;
}

複製代碼

得到的結果爲:8 20 20 36

分析如下:

1、類sizeof(A,B,C),從前面的分析可以得到結果爲8 20 20;

2、sizeof(D) = 

12【父類B的內容,包括指向虛函數的虛指針(4,合併類D的虛函數)、虛基類指針列表vptr_B_A(4)、數據成員(4)】

+ 12【父類C的內容,包括指向虛函數的虛指針(4)、虛基類指針列表vptr_C_A(4)、數據成員(4)】

+ 4(類D的的數據成員)+ 4(類A虛函數的虛指針)+ 4(類A的數據成員)= 36。

     

可見,類D中只包含了類A的一份副本,虛繼承很好地解決了多重繼承中的二義性問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章