虚继承
存在的理由
存在即合理
虽然我们相信这句话,但是为什么合理呢?是什么促使它存在的呢?
我们引出一个概念,菱形继承
什么是菱形继承:
class A //大小为4
{
public:
int a;
};
class B : public A
{
public:
int b;
};
class C : public A
{
public:
int c;
};
class D :public B, public C
{
public:
int d;
};
我们画出它的类图,会发现是一个菱形
当我们实例化D类,对象是d,并且调用d.a;
那么会出现二义性的问题。
通过引入虚函数,可以解决以下问题:
+ 二义性问题
+ 浪费存储空间
实现原理
- 每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)
- 虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了
- 当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
- 实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。
- 我的理解是通过偏移地址,找到虚基类成员,如果两个父类的父类是一个类,类似于B的父类是A,C的父类是A,B,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:
int d;
};
注意virtual的位置。