1.菱形继承:
1>继承模型:
2>代码测试并查看内存模型
#include<iostream>
using namespace std;
class A
{
public:
A(int a = 5)
:_a(a)
{
cout<<"A的构造被调用"<<endl;
}
~A()
{
cout<<"A被析构"<<endl;
}
private:
int _a;
};
class B:public A
{
public:
B(int b = 0)
:_b(b)
{
cout<<"B的构造被调用"<<endl;
}
~B()
{
cout<<"B被析构"<<endl;
}
private:
int _b;
};
class C:public A
{
public:
C(int c = 0)
:_c(c)
{
cout<<"C的构造被调用"<<endl;
}
~C()
{
cout<<"C被析构"<<endl;
}
private:
int _c;
};
class D:public B,public C
{
public:
D(int d = 0)
:_d(d)
{
cout<<"D的构造被调用"<<endl;
}
~D()
{
cout<<"D被析构"<<endl;
}
private:
int _d;
};
void Test()
{
B b(10);
C c(20);
D d(30);
cout<<"A类的大小是:"<<sizeof(A)<<endl;
cout<<"B类的大小是:"<<sizeof(B)<<endl;
cout<<"C类的大小是:"<<sizeof(C)<<endl;
cout<<"D类的大小是:"<<sizeof(D)<<endl;
}
程序运行结果及分析:
内存分布图:
从内存分布图和程序的运行结果我们可以看出,在D类的对象d中,存在A类的对象成员的两份,就存在数据冗余的现象。如果我们想要查看d对象中的_a成员(由于没有给出其他的公有成员函数,这里只能将_a先设为public来测试),程序就会出现这样的情况。
所以,菱形继承不仅仅存在数据冗余的问题,还存在二义性的问题,那么在这里,我们如何处理这个二义性的问题?
处理办法:加上类的作用域限定符。
如图:
当然,这样的办法虽然可以解决二义性的问题,仍然不能解决数据冗余的问题。
2.虚继承
虚继承就是来解决菱形继承中出现的两个问题。
1>继承模型:
2>代码测试并查看内存模型:
代码:在上边的代码的基础上进行修改:
将B和C的继承都变成虚继承,对应修改成以下的两行代码:
class B:virtual public A
class C:virtual public A
运行结果:
内存分布图:
关于虚继承,就先整理到这里,之后还会涉及到含有虚函数的虚继承,其中必然包含虚表,所以,涉及到虚继承(与虚基表有关),并不一定和虚表有关。