现在的位置: 首页 > 综合 > 正文

虚拟继承内存剖析

2013年12月07日 ⁄ 综合 ⁄ 共 3484字 ⁄ 字号 评论关闭

C++对象的内存布局因不同的编译器有所差异,但是不同继承的内存布局比较简单,在涉及到虚函数,虚继承时,显得尤为复杂。

本内容试图在vs编译器下剖析其实景。

 (以下都考虑含有虚函数的情况)

1. 对于单虚继承关系:

   class A{

       public:

               void f()

                 { cout<<"Base:A"<<endl;

                  }

   };

   class B:public virtual A{

          public:

               void f()

                 { cout<<"Derive B"<<endl;

                  }

               void g(){}

  };

B对象内存空间如下图所示:

 

 

2. 对于多虚继承  如 

 class D:public virtual A,public virtual B,public virtual C

  {   ...  };

D类对象内存空间如下所示:

 

3. 假设有如下其继承关系:

 


 

其类代码如下:B1,B2分别虚拟继承B,D普通继承B1,B2.

 

#include <iostream>
using namespace std;

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 virtual 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:  virtual 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;}
 
       
 
};

class E{

};

void main(){
    typedef void(*Fun)(void);
    int** pVtab = NULL;
    Fun pFun = NULL;
    D dd;
 
 
    pVtab = (int**)&dd;
 
    cout << "[0] D::B1::_vptr->" <<" ["<<pVtab<<"]"<< endl;
 
    pFun = (Fun)pVtab[0][0];
 
    cout << "     [0] ";    pFun(); //D::f1();
 
    pFun = (Fun)pVtab[0][1];
 
    cout << "     [1] ";    pFun(); //B1::Bf1();
 
    pFun = (Fun)pVtab[0][2];
 
    cout << "     [2] ";    pFun(); //D::Df();
 
    pFun = (Fun)pVtab[0][3];
 
    cout << "     [3] ";
 
    cout << pFun << endl;
 
 
 
    //cout << pVtab[4][2] << endl;
 
    cout << "[1] = 0x";
 
    cout <<  (int*)((&dd)+1) <<" ["<<pVtab+1<<"]"<< endl; //????
	cout<< "     [0] "<<pVtab[1][0]<<endl;
	cout<< "     [1] "<<pVtab[1][1]<<endl;
	cout<< "     [2] "<<pVtab[1][2]<<endl;

 
 
 
    cout << "[2] B1::ib1 = ";
 
    cout << *((int*)(&dd)+2) <<" ["<<pVtab+2<<"]"<< endl; //B1::ib1
 
    cout << "[3] B1::cb1 = ";
 
    cout << (char)*((int*)(&dd)+3) << " ["<<pVtab+3<<"]"<< endl; //B1::cb1
 
 
 
    //---------------------
 
    cout << "[4] D::B2::_vptr->" <<" ["<<pVtab+4<<"]"<< endl;
 
    pFun = (Fun)pVtab[4][0];
 
    cout << "     [0] ";    pFun(); //D::f2();
 
    pFun = (Fun)pVtab[4][1];
 
    cout << "     [1] ";    pFun(); //B2::Bf2();
 
    pFun = (Fun)pVtab[4][2];
 
    cout << "     [2] ";
 
    cout << pFun << endl;
 
   
 
    cout << "[5] = 0x";
 
    cout << *((int*)(&dd)+5) << " ["<<pVtab+5<<"]"<< endl; // ???
	cout<< "     [0] "<<pVtab[5][0]<<endl;
	cout<< "     [1] "<<pVtab[5][1]<<endl;
	cout<< "     [2] "<<pVtab[5][2]<<endl;
 
 
 
    cout << "[6] B2::ib2 = ";
 
    cout << (int)*((int*)(&dd)+6) <<" ["<<pVtab+6<<"]"<< endl; //B2::ib2
 
    cout << "[7] B2::cb2 = ";
 
    cout << (char)*((int*)(&dd)+7) <<" ["<<pVtab+7<<"]"<< endl;//B2::cb2
 
 
 
    cout << "[8] D::id = ";
 
    cout << *((int*)(&dd)+8) << " ["<<pVtab+8<<"]"<< endl; //D::id
 
    cout << "[9] D::cd = ";
 
    cout << (char)*((int*)(&dd)+9) << " ["<<pVtab+9<<"]"<< endl;//D::cd
 
 
 
    cout << "[10]  = 0x";
 
    cout << (int*)*((int*)(&dd)+10) << " ["<<pVtab+10<<"]"<< endl;
 
    //---------------------
 
    cout << "[11] D::B::_vptr->" <<" ["<<pVtab+11<<"]"<< endl;
 
    pFun = (Fun)pVtab[11][0];
 
    cout << "     [0] ";    pFun(); //D::f();
 
    pFun = (Fun)pVtab[11][1];
 
    cout << "     [1] ";    pFun(); //B::Bf();
 
    pFun = (Fun)pVtab[11][2];
 
    cout << "     [2] ";
 
    cout << pFun << endl;
 
 
 
    cout << "[12] B::ib = ";
 
    cout << *((int*)(&dd)+12) << " ["<<pVtab+12<<"]"<< endl; //B::ib
 
    cout << "[13] B::cb = ";
 
    cout << (char)*((int*)(&dd)+13) <<" ["<<pVtab+13<<"]"<< endl;//B::cb
}

 

 运行后:结果及解释如下图1所示:

对于普通继承来说,如果基类或派生类中含有 虚函数,则派生类对象空间必有虚函数表指针,否则没有虚函数指针;

对于虚继承来说,派生类对象空间必有虚基类表指针,如果基类或派生类含有虚函数,则存在虚函数表指针;

这对于计算派生类对象的大小(sizeof)很有关系,必须加以重视。

 

 

图1:虚拟继承内存图

说明:“间隔”产生的原因是派生类重写了基类的虚函数。如果没重写,则这一项没有

 

参考:http://blog.csdn.net/haoel/article/details/3081385

          

http://www.cnblogs.com/cswuyg/archive/2010/08/20/1804113.html

 

 

抱歉!评论已关闭.