C++虛繼承與普通繼承的區別

虛繼承的時候在子類的對象中會多出一個叫虛類指針的大小,有的資料說這個指針指向的內存裏面包含了該子類的偏移量和到基類的距離。但是我跟蹤過這段內存,發現裏面的數據沒有規律,也找不到更多的支撐材料,權且先知道子類的對象裏面會有這麼一個東西吧。

先總結虛擬繼承中比較特殊的地方,希望能夠對大家有所幫助:

虛繼承時子類的虛函數不再是添加到父類部分的虛表中,而在普通的繼承中確實直接添加到父類的虛表中,這就意味着如果虛繼承中子類父類都有各自的虛函數,在子類裏面就會多出一個虛表指針,而普通的繼承卻不會這樣。代碼說明:

class B
{
public:
 char b[3];
public:
 virtual void bb()
 {
  cout<<"B"<<endl;
 }
};

class C:public virtual B
{
public:
 char c[3];
public:
 virtual void cc()
 {
  cout<<"C"<<endl;
 }
};

int main()
{
 C c;

 c.c[0]=1;
 c.c[1]=2;
 c.c[3]=3;

 c.b[0]=4;
 c.b[1]=5;
 c.b[2]=6;

 C*ptr=&c;
 void (*PtrFun)();
 int *p,*p2;

 memcpy(&p,&ptr,4);//使得p指向c的地址
 memcpy(&p2,p,4);  //使得p2指向虛表的地址
 memcpy(&PtrFun,p2,4);
 PtrFun();//調用C的虛函數表明前四個字節是C的虛函數表的位置

 p+=1;
 //跳過C的虛類指針
 p+=1;
 //跳過C的數組地址
 p+=1;

 memcpy(&p2,p,4);//定位到B的虛表地址
 memcpy(&PtrFun,p2,4);  //調用B的虛函數                 
 PtrFun();

 cout<<sizeof(c)<<endl;
}



普通繼承中子類中則不會多出虛類指針,子類也不會有自己單獨的虛函數列表,子類的虛函數會被嵌到基類部分的虛函數表的後面,代碼如下:

int main()
{
 C c;

 c.c[0]=1;
 c.c[1]=2;
 c.c[3]=3;

 c.b[0]=4;
 c.b[1]=5;
 c.b[2]=6;

 C*ptr=&c;
 void (*PtrFun)();
 int *p,*p2;

 memcpy(&p,&ptr,4);//使得p指向c的地址
 memcpy(&p2,p,4);  //使得p2指向虛表的地址
 memcpy(&PtrFun,p2,4);
 PtrFun();//調用C的虛函數表明前四個字節是C的虛函數表的位置

 p2+=1;
 memcpy(&PtrFun,p2,4);
 PtrFun();

 cout<<sizeof(c)<<endl;
}


從中我們不難發現虛擬繼承父類子類的內存排列方式也有很大的差別,普通繼承中父類在前,子類在後;虛擬繼承中先是子類部分的內存,接着再是父類的內存。對於虛擬繼承中的多次繼承就更奇葩了。

附上代碼,大家應該很容易看明白其中的內存是如何分佈的:

#include <iostream>
using namespace std;

class A
{
public:
 char a[3];
public:
 virtual void ba()
 {
  cout<<"A"<<endl;
 }
};

class B:public virtual  A
{
public:
 char b[3];
public:
 virtual void bb()
 {
  cout<<"B"<<endl;
 }
};

class C:public virtual B
{
public:
 char c[3];
public:
 virtual void cc()
 {
  cout<<"C"<<endl;
 }
};

int main()
{
 C c;
 C*ptr=&c;
 void (*PtrFun)();
 int *p,*p2;

 memcpy(&p,&ptr,4);//使得p指向c的地址
 memcpy(&p2,p,4);  //使得p2指向虛表的地址
 memcpy(&PtrFun,p2,4);
 PtrFun();//調用C的虛函數表明前四個字節是C的虛函數表的位置

 p+=1;
 //跳過C的虛類指針
 p+=1;
 //跳過C的數組地址
 p+=1;

 memcpy(&p2,p,4);//我覺得應該是到B的地址了,但是確實到A的地址
 memcpy(&PtrFun,p2,4);                    //大概是將A放到了前面吧
 PtrFun();//調用A的虛函數,表明此時的p所保存的是A的虛函數表的位置

 p+=1;
 //跳過A的數組地址
 p+=1;

 memcpy(&p2,p,4);
 memcpy(&PtrFun,p2,4);
    PtrFun();//調用B的虛函數,表明此時的p所保存的是B的虛表地址

 c.c[0]=1;
 c.c[1]=2;
 c.c[3]=3;

 c.b[0]=4;
 c.b[1]=5;
 c.b[2]=6;

 c.a[0]=7;
 c.a[1]=8;
 c.a[2]=9;
}


沒錯 C的內存是在前面,但是後面緊接着的不是B的內存而是C的內存,至於爲什麼會這樣分配,這個我也不知道,希望知道的人可以指點一下。(普通繼承下是 C B A)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章