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**)ⅆ
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