测试四:菱形虚继承
4.1、菱形普通继承(存储二义性)
#pragma vtordisp(off)
#include <iostream>
using std::cout;
using std::endl;
class B
{
public:
B() : _ib(10), _cb('B') {}
virtual void f()
{
cout << "B::f()" << endl;
}
virtual void Bf()
{
cout << "B::Bf()" << endl;
}
private:
int _ib;
char _cb;
};
class B1 : /*virtual*/ public B
{
public:
B1() : _ib1(100), _cb1('1') {}
virtual void f()
{
cout << "B1::f()" << endl;
}
virtual void f1()
{
cout << "B1::f1()" << endl;
}
virtual void Bf1()
{
cout << "B1::Bf1()" << endl;
}
private:
int _ib1;
char _cb1;
};
class B2 : /*virtual*/ public B
{
public:
B2() : _ib2(1000), _cb2('2') {}
virtual void f()
{
cout << "B2::f()" << endl;
}
virtual void f2()
{
cout << "B2::f2()" << endl;
}
virtual void Bf2()
{
cout << "B2::Bf2()" << endl;
}
private:
int _ib2;
char _cb2;
};
class D : public B1, public B2
{
public:
D() : _id(10000), _cd('3') {}
virtual void f()
{
cout << "D::f()" << endl;
}
virtual void f1()
{
cout << "D::f1()" << endl;
}
virtual void f2()
{
cout << "D::f2()" << endl;
}
virtual void Df()
{
cout << "D::Df()" << endl;
}
private:
int _id;
char _cd;
};
int main(void)
{
D d;
cout << sizeof(d) << endl;
return 0;
}
内存布局:
D中有从B1中继承来的B的数据成员,也有从B2中继承来的B的数据成员,如果d访问Bf()函数的话就会造成二义性,不知道是要访问B1中从B继承来的Bf还是B2中从B继承来的Bf
所以需要虚拟继承来解决二义性问题
4.2、菱形虚拟继承
class B
{
public:
B() : _ib(10), _cb('B') {}
virtual void f()
{
cout << "B::f()" << endl;
}
virtual void Bf()
{
cout << "B::Bf()" << endl;
}
private:
int _ib;
char _cb;
};
class B1 : virtual public B
{
public:
B1() : _ib1(100), _cb1('1') {}
virtual void f()
{
cout << "B1::f()" << endl;
}
virtual void f1()
{
cout << "B1::f1()" << endl;
}
virtual void Bf1()
{
cout << "B1::Bf1()" << endl;
}
private:
int _ib1;
char _cb1;
};
class B2 : virtual public B
{
public:
B2() : _ib2(1000), _cb2('2') {}
virtual void f()
{
cout << "B2::f()" << endl;
}
virtual void f2()
{
cout << "B2::f2()" << endl;
}
virtual void Bf2()
{
cout << "B2::Bf2()" << endl;
}
private:
int _ib2;
char _cb2;
};
class D : public B1, public B2
{
public:
D() : _id(10000), _cd('3') {}
virtual void f()
{
cout << "D::f()" << endl;
}
virtual void f1()
{
cout << "D::f1()" << endl;
}
virtual void f2()
{
cout << "D::f2()" << endl;
}
virtual void Df()
{
cout << "D::Df()" << endl;
}
private:
int _id;
char _cd;
};
B1和B2都虚拟继承自B,内存布局:
D继承自B1和B2,B1和B2虚拟继承自B,B1和B2都有自己的虚基指针,指向自己的虚基表,虚基表中第二个偏移量是各自的虚基指针距离虚基类B子对象的偏移,虚基类B的内存布局只有一份,不会造成二义性,所以就解决了二义性的问题
看一下linux下的内存布局:这里是gdb查看
也可以使用下面的命令生成内存文件查看:
g++ -fdump-class-hierarchy virtual3.cpp
这个文件就是内存布局文件
linux下的d对象里面没有虚基指针,B的内存布局只有一份,也没有二义性问题
这里和vs上的不一样,毕竟编译器不一样,本文测试的是vs下的,就不深入探索linux环境下的类内存布局了
总结:
虚拟继承能够解决二义性问题,因为是虚拟继承就有虚基指针,虚基指针指向虚基表,虚基表里第一条内容表示的是该虚基指针距离所在的子对象的首地址的偏移,虚基表的第二条内容表示的是该虚基指针距离虚基类子对象的首地址的偏移,虚基类子对象只有一份,就解决了二义性的问题