#include <iostream>
using namespace std;
class A
{
virtual void f(){};
};
class B : public virtual A{
virtual void f(){};
};
class C: public virtual A{
virtual void f(){};
virtual void t(){};
};
int main()
{
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
}
此題在vc6.0下結果是 8 12。
回顧一下虛繼承的概念:虛繼承主要解決在多重繼承中的菱形繼承問題,也就是說 B和C類同時繼承了A類,然後D類繼承了B,C類,那麼D類的虛表就會有重複的函數指針,虛繼承就不會了……。實現方法是,在子類中保存一個父類(虛繼承類)的實體,同時保存一個指針指向這個實體。指針+實體都是屬於子類,所以sizeof會將兩者也算在內。
cout<<sizeof(B)<<endl; 結果是8原因是 sizeof(A)加上 指向A實體的指針。注意此時沒有屬於B的虛指針。也就是說B沒有自己的虛函數。
cout<<sizeof(C)<<endl; C B區別在於C中有一個屬於自己的虛函數,所以加上了一個虛指針的大小 所有爲12
最後我們來看一個完整的例子以及內存結構佈局。圖後有相關代碼。
有了之前的那個思想,我來講解下 各個結構體的 sizeof();
代碼如下:
struct A
{
A(int v=100):X(v){};
virtual void foo(void){}
int X;
};
A:很簡單 一個虛表指針 +一個 X 一共是8byte
struct B :virtual public A
{
B(int v=10):Y(v),A(100){};
virtual void fooB(void){}
int Y;
};
B:虛繼承,OK 那就是 sizeof(A)+一個指向虛基類的指針4byte+判斷B中的虛函數是不是從A繼承的,如果是則這一部分是0,如果不是則還要再加4byte 存放 虛表 那麼 B一共就是20byte。
struct C : virtual public A
{
C(int v=20):Z(v),A(100){}
virtual void fooC(void){}
int Z;
};
C的分析同A
struct D : public B, public C
{
D(int v =40):B(10),C(20),A(100),L(v){}
virtual void fooD(void){}
int L;
};
D:公共繼承B,C,那麼 直接 sizeof(b)+sizeof(C)+自己的一個虛指針-因爲B,C都是虛繼承A,那麼B和C中關於A的指針只要保存一個,所以要減去4個字節,那麼D最後一共就是40byte OK
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,C都繼承了A,D繼承了B,C,那麼D關於 A的引用只有一次,而不是 普通繼承的 對於A引用了兩次……
所以上面分析的都是浮雲 沒用的東西
轉自:http://blog.163.com/redhumor@126/blog/static/19554784201131174216260/