虚基类/虚基表/虚函数表之间的关系
class A
{
public:
virtual void func()
{}
public:
int _a;
};
class B : virtual public A
{
public:
virtual void func()
{}
virtual void func1()
{}
public:
int _b;
};
class C : virtual public A
{
public:
virtual void func()
{}
public:
int _c;
};
class D : public B, public C
{
public:
//如果不重写会报错
virtual void func()
{}
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}
补坑:虚基表中的距离A的偏移量没有存在第一个位置,它存在第二个位置,跟这里多多少少有点关系。
如果在腰部(B、C)不使用虚继承,且不重写A类中的func函数,不会有什么问题。
如果在腰部(B、C)不使用虚继承,且B、C重写了A中的func函数,也不会有问题。
因为它们现在就和多继承一样,各自有各自的虚表,子类对象D有一个B,有一个C,B有一个虚表,C有一个虚表,各自玩各自的,反正A有两份,无所谓。
当在腰部使用虚继承后,编译就会报错,为什么?
因为这个时候对象模型已经变成这个样子了:A同时属于B和C,在B、C中各自有一份距离A偏移量的虚基表,解决了数据冗余二义性。
而A中有一个虚函数那就有一份虚表,存的是虚函数地址。但是B、C都重写func函数,B、C是共享一个A,那你说子类D是放B的虚函数还是C的虚函数呢?
这个时候就会出现“D” : “void A::func(void)”的不明确继承的报错。
要处理这个问题只能在D中再重写一下func。我不用你B的也不用你C的了。
还有一个问题,如果我在B/C中增加一个虚函数func1,B继承了A,C继承了A,现在只有同一份A,那B、C的虚函数都往A的虚表里面放吗?
因为A是公共的,所以就不会再放入A的虚表里面了,B会建立自己的虚表。我们通过内存发现B的对象模型中在虚基表的偏移量前面多存了一个指针,这个指针存的是距离自己建立的虚表的指针的偏移量。B/C不仅继承了A的虚表指针,如果自己新增虚函数,自己也会建立虚表.
中在虚基表的偏移量前面多存了一个指针,这个指针存的是距离自己建立的虚表的指针的偏移量。B/C不仅继承了A的虚表指针,如果自己新增虚函数,自己也会建立虚表.
正常的继承我们发现先继承的在前面,而虚拟继承改变了对象模型:a反而在最下面且继承时既没有放在B里面也没有放在C里面,编译器把它放在了公共区域。实际上B/C的对象模型也被改了.