c++虛繼承對象的內存佈局(修改版)

c++虛繼承對象的內存佈局(修改版)

             

網上關於c++對象佈局的文章挺多,而且《深度探索c++對象模型》(Inside TheC++ Object Model 侯捷譯)一書中也很詳細地介紹。如果你一點都不瞭解C++對象的佈局,我推薦你看看《深度探索c++對象模型》的第三章,如果你意猶未盡下面的兩個系列都很不錯:

一是陳皓的《C++ 對象的內存佈局》圖文並貌,寫得很是詳細。地址是http://blog.csdn.net/haoel/archive/2008/10/15/3081328.aspx

二是玄機逸士的《對象內存佈局》系列則幾乎把每種可能性列出來了,尤爲詳盡。地址是http://blog.csdn.net/pathuang68/archive/2009/04/23/4101970.aspx

讀了以上好文,對於c++對象的佈局其實應該是山水瞭然於胸了,不過我最在寫一個用c++模仿C#事件機制的東東,但發覺得有很幾處細節不是很明瞭,而且陳皓朋友也在最後提出了一個問題,雖然有網友答之,仍語言不詳。而我卻必需深入瞭解此,才能真正實做出C++的事件。

此文應該算是狗尾續貂之作,高手可能會不屑一顧。不過希望還是對一些朋友有幫助。因爲對於普通類的對象佈局,前人備述已,我也不太可能寫出什麼新意來,更多的是因爲我比較懶。呵呵,本文所探討的就是那種極端複雜的菱形結構如下:

class A ;

class B : virtual public A;

class C : virtual public B;

class D : public B,public C;

    好了,來了,我們從最基礎的的討論起。當c++支持virtual baseclass 時,就會多了一些額外負擔,當class 中內含一個或多個virtual base class subobject時,將分成兩個部分,一個不變局部和一個共享局部。最初的方案是爲每一個虛基類安插一個指針指向這個虛基類,其缺點是爲了負擔太重,而且當虛繼承鏈加長時,導致間接存取時間加長(需通過多次跳轉)。因此有兩種解決方案(《深入》一書中所提)

一、是引入virtual base class table,不管多少個虛基類,總是隻有一個指針指向它,這個virtual base classtable(VBTBL)包括真正的 virtualbase class 指針。

二、Bjarne的辦法是在virtual function table中放置virtual base classoffset,而非地址,這個offsetvirtualfunction table 的負位置(正值是索引virtual function,而負值則方向盤引到virtual base class offsets)

我用vc2003觀測到的實際情況是。在類中增加一個指針(VBPTR)指向一個VBTBL,這個VBTBL的第一項記載的是從VBPTR 與本類的偏移地址,如果本類有虛函數,那麼第一項是FF FF FF FC(也就是-4),如果沒有則是零,第二項起是VBPTR與本類的虛基類的偏移值vc2003的這種方案個人覺得沒有Bjarne的好,一是要多一個指針,二是因爲VBPTR與虛函數表分開設計,也不便於修改。至於其它編譯器,因爲我跟其它編譯器不熟,所以也就沒有實測它們。

下面給出對於類定義

struct B1

{

int a;

int b;

};

struct B2

{

virtual void foo(void);

int c;

int d;

};

struct Test : virtual public B1, virtual public B2

{

virtual void func1(void);

virtual void func2(void);

virtual void func3(void);

int X;

};

一個Test 對象的內存佈局圖,我們可以清楚的看到在VS2003VBPTR以及VBTBL的結構以及其相關的內容是什麼意義。以及Bjarne的方案的優點。


代碼如下:

struct A

{

    A(int v=100):X(v){};

    virtual void foo(void){}

    int X;

};

 

struct B :virtual public A

{

    B(int v=10):Y(v),A(100){};

    virtual void fooB(void){}

    int Y;

};

 

struct C : virtual public A

{

    C(int v=20):Z(v),A(100){}

    virtual void fooC(void){}

    int Z;

};

 

 

struct D : public B, public C

{

    D(int v =40):B(10),C(20),A(100),L(v){}

    virtual void fooD(void){}

    int L;

};

 

 

int _tmain(int argc, _TCHAR* argv[])

{

   

    Aa;

    int *ptr;

    ptr= (int*)&a;

    cout<< ptr << " sizeof = " << sizeof(a) <<endl;

    for(int i=0;i<sizeof(A)/sizeof(int);i++)

    {

        if(ptr[i] < 10000)

        {

             cout<< dec << ptr[i]<<endl;

        }

        else cout << hex << ptr[i] <<" =" << hex << * ((int*)(ptr[i]))<<endl;

    }

 

    cout<< "--------------------------------------" <<endl;

 

    Bb;

    ptr= (int*)&b;

    cout<<"addr:" << ptr << " sizeof = "<< sizeof(b) <<endl;

    for(int i=0;i<sizeof(B)/sizeof(int);i++)

    {

        if(ptr[i] < 10000)

        {

             cout<< dec << ptr[i]<<endl;

        }

        else cout << hex << ptr[i] <<" =" << hex << * ((int*)(ptr[i]))<<endl;

    }

 

    cout<< "--------------------------------------" <<endl;

   

    Dd;

    ptr= (int*)&d;

    cout<<"addr:" << ptr << " sizeof = "<< sizeof(d) <<endl;

    for(int i=0;i<sizeof(D)/sizeof(int);i++)

    {

        if(ptr[i] < 10000)

        {

             cout<< dec << ptr[i]<<endl;

        }

        else cout << hex << ptr[i] <<" =" << hex << * ((int*)(ptr[i]))<<endl;

    }

    return 0;

}

參考資料:http://blog.csdn.net/BlueDog/article/details/4711169>

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