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