C++內存布局


  一直想寫一篇有關C++內存布局的文章,結合編譯器VS2010來探討C++對象模型在內存中的表現形式,主要是自己看《深度探索C++對象模型》太枯燥了,而且這本書也是較早出的,討論的編譯器都差不多過時了,所以才有這個想法,希望看官勿噴。廢話少說,let's go...

 

沒有虛函數的單繼承

  下面,我們假設有如下所示的單繼承關系:

                         

 

  請注意,在這個繼承關系中,父類,子類,都有自己的成員變量。而子類僅僅覆蓋了父類的f()函數

  源代碼如下:

class Base
{
public:
    void f(){ cout<<"Base::f()"<<endl; }
    void g(){ cout<<"Base::g()"<<endl; }
    void h(){ cout<<"Base::h()"<<endl; }
private:
    char chBase;
    int  iBase;
};

class Derive : public Base
{
public:
    void f() { cout<<"Derive::f()"<<endl; }
    void g1(){ cout<<"Derive::g()"<<endl; }
    void h1(){ cout<<"Derive::h()"<<endl; }
private:
    char chDerive;
    int  iDerive;
};

  這是沒有虛函數的單繼承,子類Derive的f()函數會覆蓋父類Base的f()函數,當使用父類指針指向子類對象,並調用f()函數時,實際調用的是父類的f()函數。因為f()函數不是虛擬函數,編譯器在編譯的時候就確定聲明什么類型的指針就調用什么類型的函數。很簡單,這里就不舉測試程序了。我們查看VC編譯時,輸出的信息可以看到父類和子類在內存中的布局如下:(注:這是VS2010輸出的信息,下文輸出這些類型信息也是)

1>class Base size(8):
1> +---
1> 0 | chBase
1>   | <alignment member> (size=3)
1> 4 | iBase
1> +---
1>class Derive size(16):
1> +---
1> | +--- (base class Base)
1> 0 | | chBase
1>   | | <alignment member> (size=3)
1> 4 | | iBase
1> | +---
1> 8 | chDerive
1>   | <alignment member> (size=3)
1>12 | iDerive

  可以看到:

    1、成員變量根據其繼承和聲明順序依次放在后面

    2、成員函數定義在類體之外

    3、調整字節對齊使bus的“運輸量”達到最高效率

 

沒有虛函數的多重繼承

  下面,我們假設有如下所示的多重繼承關系:

                  

  在這個繼承關系中,父類,子類,都有自己的成員變量。而了類分別覆蓋了父類Base1的一個函數f1()和父類Base2的一個函數f2(),並且子類也新增一個函數h()

  源代碼如下:

class Base1
{
public:
    Base1(int iBase1) : iBase1(iBase1){}
    void f1(){ cout<<"Base1::f1()"<<endl; }
    void g1(){ cout<<"Base1::g1()"<<endl; }
    void h1(){ cout<<"Base1::h1()"<<endl; }
private:
    int iBase1;
};

class Base2
{
public:
    Base2(int iBase2) : iBase2(iBase2){}
    void f2(){ cout<<"Base2::f2()"<<endl; }
    void g2(){ cout<<"Base2::g2()"<<endl; }
    void h2(){ cout<<"Base2::h2()"<<endl; }
private:
    int iBase2;
};

class Derive : public Base1, public Base2
{
public:
    Derive(int iBase1, int iBase2, int iDerive) : Base1(iBase1), Base2(iBase2), iDerive(iDerive) {}
    void f1(){ cout<<"Derive::f1()"<<endl; }
    void g2(){ cout<<"Derive::g2()"<<endl; }
    void h() { cout<<"Derive::h()"<<endl; }
private:
    int iDerive;
};

  我們通過下面的程序來查看子類實例的內存布局:下面程序中,我使用了一個指針變量p指向子類的地址。

Derive d(10, 20, 100);
int *p = (int *)&d;
cout<<endl;
cout << "     Base1::" << endl;
cout << "          iBase1 = "<<*p++<<endl;;
cout << "     Base2::" << endl;
cout << "          iBase2 = "<<*p++<<endl;
cout << "     Derive::" << endl;
cout << "          iDerive = "<<*p<<endl;;

  運行結果如下:

                                              

  父類和子類的內存布局在VC中的體現如下:

1>class Base1 size(4):
1> +---
1> 0 | iBase1
1> +---
1>class Base2 size(4):
1> +---
1> 0 | iBase2
1> +---
1>class Derive size(12):
1> +---
1> | +--- (base class Base1)
1> 0 | | iBase1
1> | +---
1> | +--- (base class Base2)
1> 4 | | iBase2
1> | +---
1> 8 | iDerive

  可以看到:

    1、在沒有虛函數的情況下,多重繼承與單繼承沒有多大區別, 父類和父類的成員變量根據其繼承和聲明順序依次存放后面,子類的成員變量放在最末尾。

 

有虛函數的單繼承

  下面,我們假設有如下所示的單繼承關系:

                                    

  在這個繼承關系中,父類,子類,都有自己的成員變量。父類有3個虛函數,分別是f(),g(),h()。子類重寫了父類的f()和g()函數,子類同時新增了虛函數h1()

  源代碼如下:

class Base
{
public:
    Base(int iBase) : iBase(iBase){}
    virtual void f(){ cout<<"Base::f()"<<endl; }
    virtual void g(){ cout<<"Base::g()"<<endl; }
    virtual void h(){ cout<<"Base::h()"<<endl; }
private:
    int iBase;
};

class Derive : public Base
{
public:
    Derive(int iBase, int iDerive) : Base(iBase), iDerive(iDerive) {}
    virtual void f() { cout<<"Derive::f()"<<endl; }
    virtual void g() { cout<<"Derive::g()"<<endl; }
    virtual void h1(){ cout<<"Derive::h1()"<<endl; }
private:
    int iDerive;
};

  我們通過下面這個小程序來查看子類實例的內存布局:下面程序中,我使用了一個指向指針的指針變量pVtable指向子類的地址,后面的測試程序也這樣來進行測試。

typedef void (*Func)();
Derive d(10, 100);
int **pVtable = (int **)&d;
Func pFun = NULL;

cout << "  [0]   Base::vftable" << endl;
pFun = (Func)pVtable[0][0];
cout << "        [0] ";
pFun();

pFun = (Func)pVtable[0][1];
cout << "        [1] ";
pFun();

pFun = (Func)pVtable[0][2];
cout << "        [2] ";
pFun();

pFun = (Func)pVtable[0][3];
cout << "        [3] "; 
pFun();

pFun = (Func)pVtable[0][4];
cout << "        [4] "<<pFun<<endl;

cout << "  [1]   Base::iBase = "<<(int)pVtable[1]<<endl;
cout << "  [2]   Derive::iDerive = "<<(int)pVtable[2]<<endl;

  運行界面如下:

                                              

  父類和子類在內存中的布局如下:

1>class Base size(8):
1> +---
1> 0 | {vfptr}
1> 4 | iBase
1> +---
1>Base::$vftable@:
1> | &Base_meta
1> |  0
1> 0 | &Base::f
1> 1 | &Base::g
1> 2 | &Base::h

1>class Derive size(12):
1> +---
1> | +--- (base class Base)
1> 0 | | {vfptr}
1> 4 | | iBase
1> | +---
1> 8 | iDerive
1> +---
1>Derive::$vftable@:
1> | &Derive_meta
1> |  0
1> 0 | &Derive::f
1> 1 | &Derive::g
1> 2 | &Base::h
1> 3 | &Derive::h1

  可以看出:

    1、虛函數表在類的最開始位置

    2、子類覆蓋父類的虛函數在虛函數表得到體現

    3、子類新增的虛函數添加到虛函數表的末尾

 

有虛函數的多繼承

  下面,我們假設有如下所示的多重繼承關系:

                             

  在這個繼承關系中,父類,子類,都有自己的成員變量。而子類多重繼承父類Base1和Base2以及Base3,都分別重寫他們的一個虛函數,並且新增了兩個虛函數derive_f1()和derive_g1()

  源代碼:

class Base1
{
public:
    Base1(int iBase1) : iBase1(iBase1){}
    virtual void f1(){ cout<<"Base1::f1()"<<endl; }
    virtual void g1(){ cout<<"Base1::g1()"<<endl; }
    virtual void h1(){ cout<<"Base1::h1()"<<endl; }
private:
    int iBase1;
};

class Base2
{
public:
    Base2(int iBase2) : iBase2(iBase2){}
    virtual void f2(){ cout<<"Base2::f2()"<<endl; }
    virtual void g2(){ cout<<"Base2::g2()"<<endl; }
    virtual void h2(){ cout<<"Base2::h2()"<<endl; }
private:
    int iBase2;
};

class Base3
{
public:
    Base3(int iBase3) : iBase3(iBase3){}
    virtual void f3(){ cout<<"Base3::f3()"<<endl; }
    virtual void g3(){ cout<<"Base3::g3()"<<endl; }
    virtual void h3(){ cout<<"Base3::h3()"<<endl; }
private:
    int iBase3;
};

class Derive : public Base1, public Base2, public Base3
{
public:
    Derive(int iBase1, int iBase2, int iBase3, int iDerive) : Base1(iBase1), Base2(iBase2), Base3(iBase3), iDerive(iDerive) {}
    virtual void f1() { cout<<"Derive::f()"<<endl; }
    virtual void g2() { cout<<"Derive::g()"<<endl; }
    virtual void h3() { cout<<"Derive::h1()"<<endl; }
    virtual void derive_f1(){ cout<<"Derive::derive_f1()"<<endl; }
    virtual void derive_g1(){ cout<<"Derive::derive_g1()"<<endl; }
private:
    int iDerive;
};

  我們用下面代碼來測試子類Derive的布局情況:

typedef void (*Func)();
Derive d(10, 20 ,30, 100);
int **pVtable = (int **)&d;
Func pFun = NULL;

cout << "  [0]   Base1::vftable" << endl;
pFun = (Func)pVtable[0][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[0][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[0][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[0][3];
cout << "            [3] "; 
pFun();

pFun = (Func)pVtable[0][4];
cout << "            [4] ";
pFun();

pFun = (Func)pVtable[0][5];
cout << "            [5] "<<pFun<<endl;

cout << "  [1]   Base1::iBase1 = " <<(int)pVtable[1]<<endl;

int pos = sizeof(Base1)/4;
cout << "  ["<<pos<<"]   Base2::vftable" << endl;
pFun = (Func)pVtable[pos][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[pos][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[pos][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[0][3];
cout << "            [3] "<<pFun<<endl;

cout << "  ["<<pos + 1<<"]   Base2::iBase2 = " <<(int)pVtable[pos + 1]<<endl;

pos += sizeof(Base2)/4;
cout << "  ["<<pos<<"]   Base3::vftable" << endl;
pFun = (Func)pVtable[pos][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[pos][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[pos][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[0][3];
cout << "            [3] "<<pFun<<endl;

pos++;
cout << "  ["<<pos<<"]   Base3::iBase3 = " <<(int)pVtable[pos]<<endl;

pos++;
cout << "  ["<<pos<<"]   Derive::iDerive = " <<(int)pVtable[pos]<<endl;

  運行界面如下:

                                      

  VC輸出窗口輸出的子類內存的布局信息如下:

1>class Derive size(28):
1> +---
1> | +--- (base class Base1)
1> 0 | | {vfptr}
1> 4 | | iBase1
1> | +---
1> | +--- (base class Base2)
1> 8 | | {vfptr}
1>12 | | iBase2
1> | +---
1> | +--- (base class Base3)
1>16 | | {vfptr}
1>20 | | iBase3
1> | +---
1>24 | iDerive
1> +---
1>Derive::$vftable@Base1@:
1> | &Derive_meta
1> |  0
1> 0 | &Derive::f1
1> 1 | &Base1::g1
1> 2 | &Base1::h1
1> 3 | &Derive::derive_f1
1> 4 | &Derive::derive_g1
1>Derive::$vftable@Base2@:
1> | -8
1> 0 | &Base2::f2
1> 1 | &Derive::g2
1> 2 | &Base2::h2
1>Derive::$vftable@Base3@:
1> | -16
1> 0 | &Base3::f3
1> 1 | &Base3::g3
1> 2 | &Derive::h3

  可以看出:

    1、在子類中的每一個父類都有一個虛函數表

    2、子類新增的虛函數,按繼承順序放在第一個父類的虛函數表中

    3、子類覆蓋父類的虛函數在每一個父類的虛函數表得到體現

 

有虛函數的重復多繼承

  下面,我們假設有如下所示的多重繼承關系:

                                   

  孩子類GrandDerive多重繼承於Derive1和Derive2。子類Derive1和Derive2繼承同一個父類Base。

  源代碼如下:

class Base
{
public:
    Base(int iBase) : iBase(iBase){}
    virtual void f(){ cout<<"Base::f()"<<endl; }
    virtual void g(){ cout<<"Base::g()"<<endl; }
    virtual void h(){ cout<<"Base::h()"<<endl; }
private:
    int iBase;
};

class Derive1 : public Base
{
public:
    Derive1(int iBase, int iDerive1) : Base(iBase), iDerive1(iDerive1) {}
    virtual void f() { cout<<"Derive1::f()"<<endl; }
    virtual void g() { cout<<"Derive1::g()"<<endl; }
    virtual void h1(){ cout<<"Derive1::h1()"<<endl; }
    virtual void derive1_f1(){ cout<<"Derive1::derive1_f1()"<<endl; }
    virtual void derive1_g1(){ cout<<"Derive1::derive1_g1()"<<endl; }
private:
    int iDerive1;
};

class Derive2 : public Base
{
public:
    Derive2(int iBase, int iDerive2) : Base(iBase), iDerive2(iDerive2) {}
    virtual void f() { cout<<"Derive2::f()"<<endl; }
    virtual void g() { cout<<"Derive2::g()"<<endl; }
    virtual void h2(){ cout<<"Derive2::h2()"<<endl; }
    virtual void derive2_f2(){ cout<<"Derive2::derive2_f2()"<<endl; }
    virtual void derive2_g2(){ cout<<"Derive2::derive2_g2()"<<endl; }
private:
    int iDerive2;
};

class GrandDerive : public Derive1, public Derive2
{
public:
    GrandDerive(int iBase, int iDerive1, int iDerive2, int iGrandDerive) : Derive1(iBase, iDerive1), Derive2(iBase, iDerive2), iGrandDerive(iGrandDerive) {}
    virtual void f() { cout<<"GrandDerive::f()"<<endl; }
    virtual void g() { cout<<"GrandDerive::g()"<<endl; }
    virtual void h() { cout<<"GrandDerive::h()"<<endl; }
    virtual void derive1_f1(){ cout<<"GrandDerive::derive1_f1()"<<endl; }
    virtual void derive2_g2(){ cout<<"GrandDerive::derive2_g2()"<<endl; }
    virtual void grandderive_f(){ cout<<"GrandDerive::grandderive_f()"<<endl; }
    virtual void grandderive_g(){ cout<<"GrandDerive::grandderive_g()"<<endl; }
private:
    int iGrandDerive;
};

  下面代碼來測試孩子類GrandDerive的布局情況:

typedef void (*Func)();
GrandDerive gd(10, 100 ,200, 1000);
int **pVtable = (int **)&gd;
Func pFun = NULL;

cout << "  [0]   Derive1::vftable" << endl;
pFun = (Func)pVtable[0][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[0][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[0][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[0][3];
cout << "            [3] "; 
pFun();

pFun = (Func)pVtable[0][4];
cout << "            [4] ";
pFun();

pFun = (Func)pVtable[0][5];
cout << "            [5] ";
pFun();

pFun = (Func)pVtable[0][6];
cout << "            [6] ";
pFun();

pFun = (Func)pVtable[0][7];
cout << "            [7] ";
pFun();

pFun = (Func)pVtable[0][8];
cout << "            [8] "<<pFun<<endl;

cout << "  [1]   Base::iBase = " <<(int)pVtable[1]<<endl;

cout << "  [2]   Derive1::iDerive1 = " <<(int)pVtable[2]<<endl;

int pos = sizeof(Derive1)/4;
cout << "  ["<<pos<<"]   Derive2::vftable" << endl;
pFun = (Func)pVtable[pos][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[pos][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[pos][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[pos][3];
cout << "            [3] "; 
pFun();

pFun = (Func)pVtable[pos][4];
cout << "            [4] ";
pFun();

pFun = (Func)pVtable[pos][5];
cout << "            [5] ";
pFun();

pFun = (Func)pVtable[pos][6];
cout << "            [6] "<<pFun<<endl;

pos++;
cout << "  ["<<pos<<"]   Base::iBase = " <<(int)pVtable[pos]<<endl;

pos++;
cout << "  ["<<pos<<"]   Derive2::iDerive2 = " <<(int)pVtable[pos]<<endl;

pos++;
cout << "  ["<<pos<<"]   GrandDerive::iGrandDerive = " <<(int)pVtable[pos]<<endl;

  運行界面如下:

                                     

  孩子類的內存布局如下:

1>class GrandDerive size(28):
1> +---
1> | +--- (base class Derive1)
1> | | +--- (base class Base)
1> 0 | | | {vfptr}
1> 4 | | | iBase
1> | | +---
1> 8 | | iDerive1
1> | +---
1> | +--- (base class Derive2)
1> | | +--- (base class Base)
1>12 | | | {vfptr}
1>16 | | | iBase
1> | | +---
1>20 | | iDerive2
1> | +---
1>24 | iGrandDerive
1> +---
1>GrandDerive::$vftable@Derive1@:
1> | &GrandDerive_meta
1> |  0
1> 0 | &GrandDerive::f
1> 1 | &GrandDerive::g
1> 2 | &GrandDerive::h
1> 3 | &Derive1::h1
1> 4 | &GrandDerive::derive1_f1
1> 5 | &Derive1::derive1_g1
1> 6 | &GrandDerive::grandderive_f
1> 7 | &GrandDerive::grandderive_g
1>GrandDerive::$vftable@Derive2@:
1> | -12
1> 0 | &thunk: this-=12; goto GrandDerive::f
1> 1 | &thunk: this-=12; goto GrandDerive::g
1> 2 | &thunk: this-=12; goto GrandDerive::h
1> 3 | &Derive2::h2
1> 4 | &Derive2::derive2_f2
1> 5 | &GrandDerive::derive2_g2

  可以看出:

    1、孩子類存在父類的兩份拷貝。

    2、孩子類的第二個父類的虛函數表,有些虛函數條目直接跳轉到第一個父類的虛函數表的同名函數的,這只是VC的實現方式而已,其他編譯器可能不是這樣。

 

有虛函數的虛擬繼承

  下面,我們假設有如下所示的多重繼承關系:

                                

  這個類圖與"有虛函數的重復多繼承"一致,主要區別在於Derive1和Derive2虛擬繼承於Base。

  源代碼如下:

class Base
{
public:
    Base(int iBase) : iBase(iBase){}
    virtual void f(){ cout<<"Base::f()"<<endl; }
    virtual void g(){ cout<<"Base::g()"<<endl; }
    virtual void h(){ cout<<"Base::h()"<<endl; }
private:
    int iBase;
};

class Derive1 : virtual public Base
{
public:
    Derive1(int iBase, int iDerive1) : Base(iBase), iDerive1(iDerive1) {}
    virtual void f() { cout<<"Derive1::f()"<<endl; }
    virtual void g() { cout<<"Derive1::g()"<<endl; }
    virtual void h1(){ cout<<"Derive1::h1()"<<endl; }
    virtual void derive1_f1(){ cout<<"Derive1::derive1_f1()"<<endl; }
    virtual void derive1_g1(){ cout<<"Derive1::derive1_g1()"<<endl; }
private:
    int iDerive1;
};

class Derive2 :virtual public Base
{
public:
    Derive2(int iBase, int iDerive2) : Base(iBase), iDerive2(iDerive2) {}
    virtual void f() { cout<<"Derive2::f()"<<endl; }
    virtual void g() { cout<<"Derive2::g()"<<endl; }
    virtual void h2(){ cout<<"Derive2::h2()"<<endl; }
    virtual void derive2_f2(){ cout<<"Derive2::derive2_f2()"<<endl; }
    virtual void derive2_g2(){ cout<<"Derive2::derive2_g2()"<<endl; }
private:
    int iDerive2;
};

class GrandDerive : public Derive1, public Derive2
{
public:
    GrandDerive(int iBase, int iDerive1, int iDerive2, int iGrandDerive) : Base(iBase), Derive1(iBase, iDerive1), Derive2(iBase, iDerive2)                                                                          , iGrandDerive(iGrandDerive) {}
    virtual void f() { cout<<"GrandDerive::f()"<<endl; }
    virtual void g() { cout<<"GrandDerive::g()"<<endl; }
    virtual void h() { cout<<"GrandDerive::h()"<<endl; }
    virtual void derive1_f1(){ cout<<"GrandDerive::derive1_f1()"<<endl; }
    virtual void derive2_g2(){ cout<<"GrandDerive::derive2_g2()"<<endl; }
    virtual void grandderive_f(){ cout<<"GrandDerive::grandderive_f()"<<endl; }
    virtual void grandderive_g(){ cout<<"GrandDerive::grandderive_g()"<<endl; }
private:
    int iGrandDerive;
};

  孩子類GrandDerive直接調用虛基類Base的構造函數,子類Derive1和Derive2在初始化自身的時候不再調用基類Base的構造函數。

  我們使用下面程序代碼來測試孩子類的布局情況:

typedef void (*Func)();
GrandDerive gd(10, 100 ,200, 1000);
int **pVtable = (int **)&gd;
Func pFun = NULL;

cout << "  [0]   Derive1::vftable" << endl;
pFun = (Func)pVtable[0][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[0][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[0][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[0][3];
cout << "            [3] "; 
pFun();

pFun = (Func)pVtable[0][4];
cout << "            [4] ";
pFun();

pFun = (Func)pVtable[0][5];
cout << "            [5] "<<pFun<<endl;

cout << "  [1]   Derive1::vbase" <<*(pVtable[1])<<endl;

cout << "  [2]   Derive1::iDerive1 = " <<(int)pVtable[2]<<endl;

cout << "  [3]   Derive2::vftable" << endl;
pFun = (Func)pVtable[3][0];
cout << "            [0] ";
pFun();

pFun = (Func)pVtable[3][1];
cout << "            [1] ";
pFun();

pFun = (Func)pVtable[3][2];
cout << "            [2] ";
pFun();

pFun = (Func)pVtable[3][3];
cout << "            [3] "<<pFun<<endl;

cout << "  [4]   Derive2::vbase" <<*(pVtable[4])<<endl;

cout << "  [5]   Derive2::iDerive1 = " <<(int)pVtable[5]<<endl;

cout << "  [6]   GrandDerive::iGrandDerive = " <<(int)pVtable[6]<<endl;

cout << "  [7]                               " <<(int)pVtable[7];  //這個不懂是什么 
cout << "  [8]   Base::vftable" << endl;
pFun = (Func)pVtable[8][0];   
cout << "            [0] "<<endl;  //這里必須加上換行符,不然運行崩潰,不懂原因   
pFun();

pFun = (Func)pVtable[8][1];      
cout << "            [1] "<<endl;  //這里必須加上換行符,不然運行崩潰,不懂原因   
pFun();

pFun = (Func)pVtable[8][2];
cout << "            [2] "<<endl;  //這里必須加上換行符,不然運行崩潰,不懂原因   
pFun();

pFun = (Func)pVtable[8][3];
cout << "            [3] "<<pFun<<endl;

cout << "  [9]   Base::iBase = " <<(int)pVtable[9]<<endl;

  運行界面如下:     

                                    

  在上面的運行界面,我有兩點疑問,已經用黃色標記,同時在上面的測試代碼中我也用注釋標明。如誰知道原因,麻煩告知,非常感謝。

  下面是VC輸出的GrandDerive的布局信息。

1>  class GrandDerive    size(40):
1>      +---
1>      | +--- (base class Derive1)
1>   0    | | {vfptr}
1>   4    | | {vbptr}
1>   8    | | iDerive1
1>      | +---
1>      | +--- (base class Derive2)
1>  12    | | {vfptr}
1>  16    | | {vbptr}
1>  20    | | iDerive2
1>      | +---
1>  24    | iGrandDerive
1>      +---
1>  28    | (vtordisp for vbase Base)  //上面就是這輸出0,
1>      +--- (virtual base Base)
1>  32    | {vfptr}
1>  36    | iBase
1>      +---
1>  
1>  GrandDerive::$vftable@Derive1@:
1>      | &GrandDerive_meta
1>      |  0
1>   0    | &Derive1::h1
1>   1    | &GrandDerive::derive1_f1
1>   2    | &Derive1::derive1_g1
1>   3    | &GrandDerive::grandderive_f
1>   4    | &GrandDerive::grandderive_g
1>  
1>  GrandDerive::$vftable@Derive2@:
1>      | -12
1>   0    | &Derive2::h2
1>   1    | &Derive2::derive2_f2
1>   2    | &GrandDerive::derive2_g2
1>  
1>  GrandDerive::$vbtable@Derive1@:
1>   0    | -4
1>   1    | 28 (GrandDerived(Derive1+4)Base)
1>  
1>  GrandDerive::$vbtable@Derive2@:
1>   0    | -4
1>   1    | 16 (GrandDerived(Derive2+4)Base)
1>  
1>  GrandDerive::$vftable@Base@:
1>      | -32
1>   0    | &(vtordisp) GrandDerive::f
1>   1    | &(vtordisp) GrandDerive::g
1>   2    | &(vtordisp) GrandDerive::h

  可以看出:

    1、虛基類放在孩子類的末尾

    2、VC實現虛基類的方式是每一個子類用一個指向虛基類表的指針vbptr,同時,子類的虛函數表不在包含父類的虛函數地址。

  

  各個編譯器實現的內存布局方式可能各不相同,在這里特指VS2010,如果在其他編譯器運行上述代碼,可能結果會不一樣。

  完!


免責聲明!

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



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