某些需求抽象成类图后,可能会出现这样的情况:类A作为类B和类C的父类并且类B和类C同时作为类D的父类。
将上方类图进行完善后,可以得到如下类图。
根据所画的类图,可以编译出如下代码,然后定义一个Delta类的对象,名叫alpha。为了简化操作,各个类中的成员变量和成员函数均设置为public权限。然后我们进行一次简单的Delta类对象alpha的数值输出。
根据上述代码,可以看到,alpha的alpha值并没有成功输出并在开始编译后报错,其原因是Beta类和Charlie类在继承了Alpha类的成员变量后Beta和Charlie中都有Alpha的成员变量,导致编译器无法识别处所输出的数值为Beta的alpha还是Charlie的alpha。
因此,如果想要输出预想的数值,应该在“alpha.”后加上“类名::”表示是哪个类的alpha,更改后的代码以及结果如下,这里以Beta类的alpha为例。
#include<iostream>
using namespace std;
class Alpha
{
public:
int alpha;
Alpha()
{
alpha = 1;
}
};
class Beta :public Alpha
{
public:
int beta;
Beta()
{
beta = 2;
}
};
class Charlie :public Alpha
{
public:
int charlie;
Charlie()
{
charlie = 3;
}
};
class Delta :public Charlie, public Beta
{
public:
int delta;
Delta()
{
delta = 4;
}
};
int main()
{
Delta alpha;
cout<<alpha.Beta::alpha<<endl;
return 0;
}
但是问题并没有彻底解决。
int main()
{
Delta alpha;
cout<<alpha.Beta::alpha<<endl;
cout << sizeof(alpha) << endl;
return 0;
}
如果将主函数中的代码加上一句,就可以看到Delta类的alpha对象所占用的空间。通过计算我们可以算出,预想的sizeof(alpha)的值应该为16,这个值可以通过四个int类型变量占用的空间数算出。
如果Beta和Charlie类继承Alpha的成员变量所占内存较大,则会大大增加代码冗余度。假设将Alpha类的成员变量替换成一个容量为100的数组,最后得到的Delta类的alpha的大小如下,这显然不符合实际需求。
所以,针对这种现象,C++中的解决方法就是将继承了Alpha类的Beta类和Charlie类设置成【虚继承】,这种方式是一种解决菱形继承数据冗余的常用方法。
#include<iostream>
using namespace std;
class Alpha
{
public:
int alpha;
Alpha()
{
alpha = 1;
}
};
class Beta:virtual public Alpha
{
public:
int beta;
Beta()
{
beta = 2;
}
};
class Charlie:virtual public Alpha
{
public:
int charlie;
Charlie()
{
charlie = 3;
}
};
class Delta :public Charlie,public Beta
{
public:
int delta;
Delta()
{
delta = 4;
}
};
int main()
{
Delta alpha;
cout << alpha.alpha << endl;
cout << sizeof(alpha) << endl;
return 0;
}
//虚继承:解决菱形继承的数据冗余
通过这种方式更改的代码输出的结果如下。
虽然在Alpha类的成员变量为alpha时,alpha占用的空间确实比非虚继承的alpha占用的空间多,但如果alpha作为一个大容量的成员变量,这种方法的优势就能显现出来。
虚继承的sizeof(alpha)所占空间大小
虚继承的sizeof(alpha)所占空间大小