程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ 對象的內存布局(下)

C++ 對象的內存布局(下)

編輯:C++入門知識

 重復繼承
 
下面我們再來看看,發生重復繼承的情況。所謂重復繼承,也就是某個基類被間接地重復繼承了多次。
 
下圖是一個繼承圖,我們重載了父類的f()函數。
 


其類繼承的源代碼如下所示。其中,每個類都有兩個變量,一個是整形(4字節),一個是字符(1字節),而且還有自己的虛函數,自己overwrite父類的虛函數。如子類D中,f()覆蓋了超類的函數, f1() 和f2() 覆蓋了其父類的虛函數,Df()為自己的虛函數。
 
class B
{
    public:
        int ib;
        char cb;
    public:
        B():ib(0),cb(B) {}
 
        virtual void f() { cout << "B::f()" << endl;}
        virtual void Bf() { cout << "B::Bf()" << endl;}
};
class B1 :  public B
{
    public:
        int ib1;
        char cb1;
    public:
        B1():ib1(11),cb1(1) {}
 
        virtual void f() { cout << "B1::f()" << endl;}
        virtual void f1() { cout << "B1::f1()" << endl;}
        virtual void Bf1() { cout << "B1::Bf1()" << endl;}
 
};
class B2:  public B
{
    public:
        int ib2;
        char cb2;
    public:
        B2():ib2(12),cb2(2) {}
 
        virtual void f() { cout << "B2::f()" << endl;}
        virtual void f2() { cout << "B2::f2()" << endl;}
        virtual void Bf2() { cout << "B2::Bf2()" << endl;}
       
};
 
class D : public B1, public B2
{
    public:
        int id;
        char cd;
    public:
        D():id(100),cd(D) {}
 
        virtual void f() { cout << "D::f()" << endl;}
        virtual void f1() { cout << "D::f1()" << endl;}
        virtual void f2() { cout << "D::f2()" << endl;}
        virtual void Df() { cout << "D::Df()" << endl;}
       
};
我們用來存取子類內存布局的代碼如下所示:(在VC++ 2003和G++ 3.4.4下)
    typedef void(*Fun)(void);
    int** pVtab = NULL;
    Fun pFun = NULL;
 
    D d;
    pVtab = (int**)&d;
    cout << "[0] D::B1::_vptr->" << endl;
    pFun = (Fun)pVtab[0][0];
    cout << "     [0] ";    pFun();
    pFun = (Fun)pVtab[0][1];
    cout << "     [1] ";    pFun();
    pFun = (Fun)pVtab[0][2];
    cout << "     [2] ";    pFun();
    pFun = (Fun)pVtab[0][3];
    cout << "     [3] ";    pFun();
    pFun = (Fun)pVtab[0][4];
    cout << "     [4] ";    pFun();
    pFun = (Fun)pVtab[0][5];
    cout << "     [5] 0x" << pFun << endl;
   
    cout << "[1] B::ib = " << (int)pVtab[1] << endl;
    cout << "[2] B::cb = " << (char)pVtab[2] << endl;
    cout << "[3] B1::ib1 = " << (int)pVtab[3] << endl;
    cout << "[4] B1::cb1 = " << (char)pVtab[4] << endl;
 
    cout << "[5] D::B2::_vptr->" << endl;
    pFun = (Fun)pVtab[5][0];
    cout << "     [0] ";    pFun();
    pFun = (Fun)pVtab[5][1];
    cout << "     [1] ";    pFun();
    pFun = (Fun)pVtab[5][2];
    cout << "     [2] ";    pFun();
    pFun = (Fun)pVtab[5][3];
    cout << "     [3] ";    pFun();
    pFun = (Fun)pVtab[5][4];
    cout << "     [4] 0x" << pFun << endl;
 
    cout << "[6] B::ib = " << (int)pVtab[6] << endl;
    cout << "[7] B::cb = " << (char)pVtab[7] << endl;   
    cout << "[8] B2::ib2 = " << (int)pVtab[8] << endl;
    cout << "[9] B2::cb2 = " << (char)pVtab[9] << endl;
 
    cout << "[10] D::id = " << (int)pVtab[10] << endl;
    cout << "[11] D::cd = " << (char)pVtab[11] << endl;
 
程序運行結果如下:


GCC 3.4.4 VC++ 2003
[0] D::B1::_vptr->
     [0] D::f()
     [1] B::Bf()
     [2] D::f1()
     [3] B1::Bf1()
     [4] D::f2()
     [5] 0x1
[1] B::ib = 0
[2] B::cb = B
[3] B1::ib1 = 11
[4] B1::cb1 = 1
[5] D::B2::_vptr->
     [0] D::f()
     [1] B::Bf()
     [2] D::f2()
     [3] B2::Bf2()
     [4] 0x0
[6] B::ib = 0
[7] B::cb = B
[8] B2::ib2 = 12
[9] B2::cb2 = 2
[10] D::id = 100
[11] D::cd = D [0] D::B1::_vptr->
     [0] D::f()
     [1] B::Bf()
     [2] D::f1()
     [3] B1::Bf1()
     [4] D::Df()
     [5] 0x00000000
[1] B::ib = 0
[2] B::cb = B
[3] B1::ib1 = 11
[4] B1::cb1 = 1
[5] D::B2::_vptr->
     [0] D::f()
     [1] B::Bf()
     [2] D::f2()
     [3] B2::Bf2()
     [4] 0x00000000
[6] B::ib = 0
[7] B::cb = B
[8] B2::ib2 = 12
[9] B2::cb2 = 2
[10] D::id = 100
[11] D::cd = D


下面是對於子類實例中的虛函數表的圖:
 
 
 
 

我們可以看見,最頂端的父類B其成員變量存在於B1和B2中,並被D給繼承下去了。而在D中,其有B1和B2的實例,於是B的成員在D的實例中存在兩份,一份是B1繼承而來的,另一份是B2繼承而來的。所以,如果我們使用以下語句,則會產生二義性編譯錯誤:
 
D d;
d.ib = 0;               //二義性錯誤
d.B1::ib = 1;           //正確
d.B2::ib = 2;           //正確

注意

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved