class A{
public:
A(){ptr= "abcdefg";};
~A(){};
virtualvoid print(){
printf("%s\r\n",ptr);
}
virtualvoid printA(){
printf("A::%s\r\n",ptr);
}
public:
char*ptr;
};
class B:virtual public A{
public:
B(){ptr= "BBBBBBBBBBBBBBB";bv = 0xbbbbbbbb;}
~B(){};
virtualvoid print(){
printf("B::Print[%s]\r\n",ptr);
}
virtualvoid printB(){
printf("B::Print1[%s]\r\n",ptr);
}
public:
intbv;
};
class C:virtual public A{
public:
C(){ptr= "CCCCCCCCCCCCCCCCCCC";cv =0xcccccccc;}
~C(){};
virtualvoid print(){
printf("C::[%s][%s]\r\n",ptr,ptr);
}
virtualvoid printC(){
printf("C::[%s][%s]\r\n",ptr,ptr);
}
private:
intcv;
};
class D:public B,public C{
public:
D(){v=0xdddddddd;}
~D(){};
virtualvoid print(){
printf("D::[%s][%s]\r\n",A::ptr,B::ptr);
}
private:
intv;
};
上面例子是虛繼承那麼D的記憶體布局
B::Vfptr |
D相對於B建立的虛函數表,其中不包括A虛函數 |
B::BToAOfsetPtr |
B對象開始到A對象實體的位移值的地址(B::BToAOfsetPtr+4) |
B::MemberVerb |
B成員變數 |
C::Vfptr |
D相對於C建立的虛函數表,其中不包括A虛函數 |
C::CToAOfsetPtr |
B對象開始到A對象實體的位移值的地址(C::CToAOfsetPtr+4) |
C::MemberVerb |
C成員變數 |
D::MemberVerb |
D成員變數 |
00000000 |
分隔 |
A:Vfptr |
D相對於A建立的虛函數表 |
A::MemberVerb |
A成員變數 |
註:在B和C對A覆蓋的函數在D中一定要覆蓋否則編譯提示聲明不確定;子物件實體到A對象實體的位移地址要加4,那裡的內容才是正確的。
class A{
public:
A(){ptr= "abcdefg";};
~A(){};
virtualvoid print(){
printf("%s\r\n",ptr);
}
virtualvoid printA(){
printf("A::%s\r\n",ptr);
}
public:
char*ptr;
};
class B {
public:
B(){ptr= "BBBBBBBBBBBBBBB"; }
~B(){};
virtualvoid print(){
printf("B::Print[%s]\r\n",ptr);
}
virtualvoid printB(){
printf("B::Print1[%s]\r\n",ptr);
}
public:
char*ptr;
};
class C: public A, public B{
public:
C(){cv=0xcccccccc;}
~C(){};
virtualvoid print(){
printf("C::[%s][%s]\r\n",A::ptr,B::ptr);
}
virtualvoid printC(){
printf("C::[%s][%s]\r\n",A::ptr,B::ptr);
}
private:
intcv;
};
class D:public B,public C{
public:
D(){v=0xdddddddd;}
~D(){};
virtualvoid print(){
printf("D::[%s][%s]\r\n",A::ptr,B::ptr);
}
private:
intv;
};
上面例子是虛繼承那麼D的記憶體布局:
A::Vfptr |
D相對於A,C建立的虛函數表 |
A::MemberVerb |
A成員變數 |
B::Vfptr |
D相對於B,C建立的虛函數表 |
B::MemberVerb |
B成員變數 |
C::MemberVerb |
C成員變數 |
D::MemberVerb |
D成員變數 |
註:當多個父類有同名成員時要指名範圍
關於析構:
類的解構函式要重設自己的虛擬函數表指標,是為了它被其它類繼承時它作為一個父類,子類析構調用完後再調用它時可以屏蔽子類對自己的覆蓋;因為這時子類部分的資源已經被釋放,如果不重設虛擬函數表那麼解構函式調用的函數如果被子類覆蓋,則會調用子類的函數而不是它本身的。