c++虚拟继承
http://blog.csdn.net/bluedog/article/details/4711169
先看下代碼:
struct A {A(int v=100):X(v){};virtual void foo(void){}int X; };struct B :virtual public A {B(int v=10):Y(v),A(100){};virtual void fooB(void){}int Y; };struct C : virtual public A {C(int v=20):Z(v),A(100){}virtual void fooC(void){}int Z; };struct D : public B, public C {D(int v =40):B(10),C(20),A(100),L(v){}virtual void fooD(void){}int L; };int _tmain(int argc, _TCHAR* argv[]) {A a;int *ptr;ptr = (int*)&a;cout << ptr << " sizeof = " << sizeof(a) <<endl;for(int i=0;i<sizeof(A)/sizeof(int);i++){if(ptr[i] < 10000){cout << dec << ptr[i]<<endl;}else cout << hex << ptr[i] <<" = " << hex << * ((int*)(ptr[i])) <<endl;}cout << "--------------------------------------" <<endl;B b;ptr = (int*)&b;cout <<"addr:" << ptr << " sizeof = " << sizeof(b) <<endl;for(int i=0;i<sizeof(B)/sizeof(int);i++){if(ptr[i] < 10000){cout << dec << ptr[i]<<endl;}else cout << hex << ptr[i] <<" = " << hex << * ((int*)(ptr[i])) <<endl;}cout << "--------------------------------------" <<endl;D d;ptr = (int*)&d;cout <<"addr:" << ptr << " sizeof = " << sizeof(d) <<endl;for(int i=0;i<sizeof(D)/sizeof(int);i++){if(ptr[i] < 10000){cout << dec << ptr[i]<<endl;}else cout << hex << ptr[i] <<" = " << hex << * ((int*)(ptr[i])) <<endl;}return 0; }如果B虛擬繼承A,則B的對象中要增加一個虛擬基類指針,其指向的表的第二項,即從本指針到虛擬基類的偏移。
例如,對象b,的虛擬基類的地址是120+8 = 128
虛擬基類在b對象的最后。
多重繼承,繼承n個類,有n個續表指針;包括n個虛基類,有n個虛基類指針。
舉個例子,
B虛繼承A,如果A中有虛函數,則B類對象的開始位置是虛表指針,第二個位置是虛基類的指針。
class A { public:A():a(1){}int a; }; class B: public virtual A { public:B():b(2){}int b; }; int main() {B* b = new B;A* a = dynamic_cast<A*>(b);if(a == b)//b先默認轉為A*,所以相等 {std::cout << "equal" << std::endl;} else {std::cout << "not equal" << std::endl;}//輸出equalif (int(b) == int(a)) {std::cout << "equal" << std::endl;} else {std::cout << "not equal" << std::endl;}//輸出not equaltypedef void (*pFun)(void);int **ptb = (int **)b;cout<<ptb[0][0]<<" "<<ptb[0][1]<<endl;cout<<&((int*)ptb)[1]/*<<" "<<ptb[1][1]*/<<endl;cout<<&((int*)ptb)[2]<<endl;cout<<"-------"<<endl;cout<<a<<endl<<b<<endl;}output:
equal
not equal
0 8
00701E5C
00701E60
-------
00701E60
00701E58
對象b的內存分布是:
虛基類的地址是 58+8 = 60
a為什么不等于b?
a指向了60的地址,而b指向的還是58
如果在虛繼承的繼承上又有多態重載?
class A { public:virtual void fun1(){cout<<"A"<<endl;}A():a(1){}int a; }; class B: virtual public A { public:B():b(2){}virtual void fun1(){cout<<"B:fun1"<<endl;}virtual void fun2(){cout<<"B:fun2"<<endl;}int b; };int main() {B* b = new B;A* a = dynamic_cast<A*>(b);if(a == b) {std::cout << "equal" << std::endl;} else {std::cout << "not equal" << std::endl;}//輸出equalif (int(b) == int(a)) {std::cout << "equal" << std::endl;} else {std::cout << "not equal" << std::endl;}//輸出not equalcout<<sizeof(B)<<endl;typedef void (*pFun)(void);int **ptb = (int **)b;/* int *ptmp = (int *)b;pFun p = (pFun)((int *)ptmp[0])[0];p();*/pFun pfun;pfun =(pFun) ptb[0][0];// cout<<ptb[0][0]<<" "<<ptb[0][1]<<endl;cout<<"first vtb"<<endl;pfun();cout<<ptb[1][0]<<" "<<ptb[1][1]<<endl;cout<<((int*)ptb)[2]<<endl;//B:bcout<<(int)ptb[3]<<endl;pfun = (pFun)ptb[4][0];cout<<"second vtb"<<endl;pfun();cout<<((int*)ptb)[5]<<endl;//A:acout<<"-------"<<endl;cout<<a<<endl<<b<<endl;}output:
equal
not equal
24
first vtb
B:fun2
-4 12
2
0
second vtb
B:fun1
1
-------
00360A18
00360A08
08 vftable ---->B:fun2()
0c ? base_psb---->-4,12
10 B:b
14 0//不知道為什么為0?
18 vftable------>B:fun1()
1c A:a
如果B類變為
class B: virtual public A
{
public:
?? ?B():b(2){}
?? ?virtual void fun1()
?? ?{
?? ? ? ?cout<<"B:fun1"<<endl;
?? ?}
?? ?void fun2()
?? ?{
?? ? ? ?cout<<"B:fun2"<<endl;
?? ?}
?? ?int b;
};
fun2不是虛函數,所以對象b的開始不是虛函數表指針,而是虛基類指針
?pFun pfun;
???
?? ?cout<<ptb[0][0]<<" "<<ptb[0][1]<<endl;
?? ?
??
???
?? ?cout<<((int*)ptb)[1]<<endl;//B:b
?? ?
?? ? pfun =(pFun) ptb[3][0];
?? ? pfun();
?? ?/*cout<<(int)ptb[3]<<endl;
?? ?pfun = (pFun)ptb[4][0];
?? ?cout<<"second vtb"<<endl;
?? ?pfun();*/
??
?? ?cout<<((int*)ptb)[4]<<endl;//A:a
?? ?cout<<"-------"<<endl;
?? ?cout<<a<<endl<<b<<endl;
output:
equal
not equal
20
0 12
2
B:fun1
1
-------
004D3DB4
004D3DA8
同樣,為什么第2項為0?
總結
- 上一篇: 无向图的直径以及树的直径
- 下一篇: c++虚函数以及虚继承图示