轉自http://blog.csdn.net/pathuang68/article/details/4105810
下面來看看虛基類對對象內存佈局的影響。虛基類的主要作用就是在所有的派生類中,保留且僅保留一份虛基類的suboject。
a. 一個虛基類的情況
#include <iostream>
using namespace std;
class Base
{
public:
int base_member;
};
class Derived : public virtual Base {};
int main(void)
{
Base b;
Derived d;
cout << sizeof(b) << endl;
cout << sizeof(d) << endl;
return 0;
}
運行結果:
注意使用了虛繼承,即class Derived : public virtual Base。這次Derived的對象大小爲什麼爲8 bytes呢?這是因爲編譯器會給Derived對象安插一個虛基類表指針vbptr,下面給出Derived對象的memory layout:
虛基類表指針vbptr指向Derived類的virtual bass class table(虛基類表),虛基類表中存放的是Derived類的虛基類表指針到虛基類實例指針的偏移量。
如果Derived有兩個虛基類,那麼這兩個虛基類的實例指針,分別位於虛基類表的第2項和第3項,最後一項爲0,意味着虛基類表的結束。虛基類表中的第1項是什麼?目前不清楚,但是它的值大部分時候爲0(請牛人指教,編譯器是VC6)。下面我們來檢驗之。
在main函數的return前,增加如下語句:
cout << "Derived object d's vbptr = " << (unsigned long*)(&d) << endl;
cout << "Address of virtual base class table = " << (unsigned long*)*(unsigned long*)(&d) << endl;
cout << "Item 1 in virtual base class table = " << *(unsigned long*)*(unsigned long*)(&d) << endl;
cout << "Item 2 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 1) << endl;
cout << "Item 3 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 2) << endl;
cout << "The address of virtual base class Base = " << (Base*)(&d) << endl;
編譯後運行結果:
不難發現,虛基類示例地址 = vbptr + offset,即0x0012FF78 = 0x0012FF74 + 4。圖示如下:
b. 我們來看看Derived有兩個虛基類的情況:
#include <iostream>
using namespace std;
class Base1
{
public:
int base1_member;
};
class Base2
{
public:
int base2_member;
};
class Derived : public virtual Base1, public virtual Base2 {};
int main(void)
{
Base1 b1;
Base2 b2;
Derived d;
cout << sizeof(b1) << endl;
cout << sizeof(b2) << endl;
cout << sizeof(d) << endl;
cout << "Derived object d's vbptr = " << (unsigned long*)(&d) << endl;
cout << "Address of virtual base class table = " << (unsigned long*)*(unsigned long*)(&d) << endl;
cout << "Item 1 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 0) << endl;
cout << "Item 2 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 1) << endl;
cout << "Item 3 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 2) << endl;
cout << "Item 3 in virtual base class table = " << *((unsigned long*)*(unsigned long*)(&d) + 3) << endl;
cout << "The address of virtual base class: Base1's instance = " << (Base1*)(&d) << endl;
cout << "The address of virtual base class: Base2's instance = " << (Base2*)(&d) << endl;
return 0;
}
編譯運行結果如下:
Derived對象的memory layout圖解如下:
不管Derived類有多少個虛基類,它只有一個vbptr和一個virtual base class table。