#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引用了两次……
所以上面分析的都是浮云 没用的东西