前言
本篇文章主要描述虚拟继承中内存分布情况,当然,可能会不太完全正确,希望大家多多指正
为什么要有虚拟继承
我们看下面一种情景:
class A
{
public:
int a;
};
class B : public A
{
public:
int b;
};
class C : public A
{
public :
int C;
};
class D : public B, public C
{
public:
void func()
{
}
};
为了更加方便理解,用图表示:
如上图,那么就会出现问题:类D中的成员变量 int a,如果访问a,就会出现二义性问题,到底是B中的a,还是C中的A,并且会造成数据冗余问题。
其中,对于二义性问题,我们加访问限定即可。例如 C::a;但对于数据冗余问题却没有办法解决。
于是C++中就引入了虚拟继承
将代码改为:
class A
{
public:
int a;
};
class B : virtual public A
{
public:
int b;
};
class C : virtual public A
{
public :
int C;
};
class D : public B, public C
{
public:
void func()
{
}
};
如果,类中带有虚函数。内存结构会变为怎样??
class A
{
public:
A(int v = 100) :X(v) {};
virtual void foo(void) {}
int X;
};
class B :virtual public A
{
public:
B(int v = 10) :Y(v), A(100) {};
virtual void fooB(void) {}
int Y;
};
class C : virtual public A
{
public:
C(int v = 20) :Z(v), A(100) {}
virtual void fooC(void) {}
int Z;
};
class D : public B, public C
{
D(int v = 40) :B(10), C(20), A(100), L(v) {}
virtual void fooD(void) {}
int L;
};
对于类A,内存布局:
对于类B,内存布局:
对于类D,内存布局:
虚拟继承和普通继承的区别
class A
{
public:
virtual void funA();
};
class B : public A
{
public:
virtual void funB();
}
class A
{
public:
virtual void funA();
};
class B : virtual public A
{
public:
virtual void funB();
}
上述两种继承有什么区别??一种普通继承,一种虚拟继承
首先,我们知道,如果一个类中有虚函数,那么就会有一个虚表,有一个指针指向这个虚表。
对于A,内存布局如下:
对于普通继承,继承的虚函数和本有的虚函数共用同一个虚表
则普通继承 B布局如下:
但对于虚拟继承来说,不管是基类还是派生类都需要有一个指针来维护自己的虚表,并且还要有一个指针指向虚基表,其中存放偏移量
虚拟继承 sizeof() 问题
有了上面的基础,来看几道题:
//第一种情况
class a
{
virtual void func();
};
class b:public virtual a
{
virtual void foo();
};
//第二种情况
class a
{
virtual void func();
};
class b :public a
{
virtual void foo();
};
//第三种情况
class a
{
virtual void func();
char x;
};
class b:public virtual a
{
virtual void foo();
};
//第四种情况
class a
{
virtual void func()
char x;
};
class b:public a
{
virtual void foo();
};
对于每种情况,分别计算 sizeof(a), sizeof(b)的大小
结果:
第一种:4,12
第二种:4,4
第三种:8,16
第四种:8,8
参照上述普通继承和虚拟继承的区别,就知道原因了。