最近在学习C++的继承,菱形继承是比较难懂的一部分,所以通过查阅资料后整理了一下思路,也和同学分享了关于菱形虚拟继承的一些东西。
菱形继承在一般情况下使用不到的,但是通过了解菱形继承,我们 可以了解编译器是如何工作的。
首先,菱形虚拟继承就是两个基类虚拟继承一个共同的超类,然后两个基类由有一个共同的派生类。
class Base
{
public:
void func()
{
cout << "Base::func"<<endl;
}
public:
int a;
};
class Base1:virtual public Base
{
public :
virtual void func1()
{
cout<<"Base1::func1" <<endl;
}
virtual void func2()
{
cout<<"Base1::func2" <<endl;
}
public :
int b1 ;
};
class Base2:virtual public Base
{
public :
virtual void func1()
{
cout<<"Base2::func1" <<endl;
}
virtual void func2()
{
cout<<"Base2::func2" <<endl;
}
public :
int b2 ;
};
class Derive : public Base1, public Base2
{
public :
virtual void func1()
{
cout<<"Derive::func1" <<endl;
}
virtual void func3()
{
cout<<"Derive::func3" <<endl;
}
pubilc :
int d1 ;
};
在这我们构造出一个Derive的对象d,调用监视窗口,看一下编译器是怎么存的。
我们可以看到,Base1和Base2中都有一个虚函数表指针,编译器就是利用虚函数表指针解决了二义性问题,而且Base1和Base2的虚函数表指针地址都不同,所以他们都有自己的虚表。
int main()
{
//Test1();
Derive d;
d.a = 1;
d.b1 = 2;
d.b2 = 3;
d.d1 = 4;
return 0;
}
之前的类的数据成员我是设为了public的,方便赋值后直接调出内存来看内存里的变化。然后给数据成员a,b1,b2,d依次赋值然后调出内存看:
所以虚拟继承的实质就是利用一个虚基类指针和一个虚函数表指针解决数据的二义性