您的位置:首页 > 编程语言 > C语言/C++

C++内存布局(下)

2016-03-07 19:08 351 查看
上一篇已经分析了基本结构体、C++简单对象和加上一般的继承之后的各种情况,这篇文章将主要在有虚继承时,C++对象的内存又是怎样分配的。

虚继承

虚继承解决了从不同途径继承的类具有共同基类的问题,使得共同基类只有一份拷贝。解决了二义性的问题,也节省了内存。

虚继承的一般类图如下所示:



sizeof(Derived) = 40 字节。经过分析,可以得到Derived类在内存中的存储结构示意图为:



总结:

各部分在内存中的存放顺序为先父类、后子类、最后公共基类,即先存放Base1、Base2,然后是Derived,最后才是Base类

对于虚拟继承,子类中会增加一个vbptr指针,它指向的值要么是0,要么是-4,表示公共基类相对于子类的偏移,也即Base类相对于Derived类的偏移。当Base类中有虚函数时,为-4;否则为0。

在VS编译器中,子类和公共基类之间会通过一个NULL指针分隔开。在其它编译器中可能没有这个字段

对于每个类的虚函数表可以依次分析:

首先是Base类,Base类的ff()函数首先被Base1覆盖,然后又被Derived类覆盖,Base类的gg()函数并未被覆盖,因此Base类的虚函数表中指向的虚函数分别为:Derived::ff()、Base::gg()。

然后是Base1类,Base1类原本定义了两个虚函数,但是ff()函数是覆盖了父类Base中的函数,因此不在Base1的虚函数表中,只有bf1()。同时子类Derived中新定义了一个hh()虚函数,要插入到内存中的第一个虚函数表,因此会插入到Base1类的虚函数表中,因而Base1类中会有Base1::bf1()、Derived::hh()两个函数

最后是Base2类,只有Base2::bf2()一个虚函数。

简单的验证代码如下所示:

typedef void (*Fun) (void );

class Base{
public:
Base():ba(333){}
int ba;
virtual void ff(){
cout<<"Base::ff()"<<endl;
}
virtual void gg(){
cout<<"Base::gg()"<<endl;
}
};

class Base1:virtual public Base{
public:
Base1():ba(11){}
int ba;
virtual  void ff(){
cout<<"Base::ff()"<<endl;
}
virtual  void Bf1(){
cout<<"Base::Bf1()"<<endl;
}
};

class Base2:virtual public Base{
public:
Base2():ba(22){}
int ba;
virtual void Bf2(){
cout<<"Base2::Bf2()"<<endl;
}
};

class Derived:public Base1,public Base2{
public:
Derived():da(55){Base1();Base2();}
int da;
void ff(){
cout<<"Derived::ff()"<<endl;
}
virtual  void hh(){
cout<<"Derived::hh()"<<endl;
}
};

int main(void){
Derived *pt=new Derived();
printf("sizeof(Derived) = %d\n",sizeof(Derived));
int len=sizeof(Derived)/4;

int** pVtab = (int**)pt;
Fun pFun;

cout<<"pt[0] :"<<endl;
for (int i=0; (Fun)pVtab[0][i]!=NULL; i++){
pFun = (Fun)pVtab[0][i];
pFun();
}
cout<<"pt[1] :"<<endl;
cout << "    ["<<0<<"] ";
cout<<(int)*pVtab[1]<<endl;

cout<<"pt[2] :"<<(int)pVtab[2]<<endl;

cout<<"pt[3] :"<<endl;
for (int i=0; (Fun)pVtab[3][i]!=NULL; i++){
pFun = (Fun)pVtab[3][i];
pFun();
}
cout<<"pt[4] :"<<endl;
cout << "    ["<<0<<"] ";
cout<<(int)*pVtab[4]<<endl;

cout<<"pt[5] :"<<(int)pVtab[5]<<endl;
cout<<"pt[6] :"<<(int)pVtab[6]<<endl;
cout<<"pt[7] :"<<(int)pVtab[7]<<endl;

cout<<"pt[8] :"<<endl;
pFun = (Fun)pVtab[8][0];
for(int i=0;(pFun = (Fun)pVtab[8][i])!=NULL;++i){
pFun();
}

cout<<"pt[9] :"<<(int)pVtab[9]<<endl;

system("pause");
return 0;
}


得到输出结果为:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: