对于菱形继承问题 C++与Java不同的解决方案
菱形继承定义
菱形继承问题是由于编程语言允许多继承所导致的. 最简单的例子如下:
class Person
{
public:
string _name; // 姓名
};
class Student : public Person
{
protected:
int _num; //学号
};
class Teacher : public Person
{
protected:
int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:
string _majorCourse; // 主修课程
};
D类在进行实例化时,类实例化顺序如下(按分支进行):
A(从 B 路径的基类 A 实例化)=> B => A(从 C 路径的基类 A 再次实例化)=> C => D,
D类在进行实例化时A类被实例化了两次,由此可能引出的二义性问题例子如下:
D d;
d._name = "李华"; //报错,C,D是通过普通(非虚拟)的方式继承A,那么D在内存中会包含两个独立的A类string _name成员变量
//这会导致菱形继承问题,即孙类中有两份祖父类的成员变量副本,变量名称相同,但存储位置不同。要访问其中某个成员变量时,需要明确指出它来自哪个父类。
d.B::_name = "李华"; //正确
d.C::_name = "李华"; //正确
原因:
在单继承情况下,编译器可以通过符号命名将成员变量在内存中唯一标识,以确保它们在使用时不会与其他成员产生冲突。在多继承情况下,如果两个基类中有相同名字的成员变量,编译器会遇到命名冲突,因此需要使用作用域解析来明确成员的来源.
如下图所示, d对象内存空间拥有2个A对象的实例空间,则两个A对象的相同名称成员变量会产生冲突。注意:区别于成员变量,成员函数为类所有. 实例化时对象的内存空间只为非静态成员变量分配内存空间. 而成员函数存放于代码段被所有类对象共享.
菱形继承问题解决(C++):
虚拟继承:虚拟继承确保无论通过哪个路径继承,只有一个A的实例存在于D中.
菱形继承问题解决(Java):
只允许单继承机制,并提出接口。一个类允许实现多个接口,接口作为功能接口不允许定义成员变量(避免二义性),且接口中声明的成员函数其派生类必须进行重写。
参考:
https://blog.youkuaiyun.com/Jdxxwu/article/details/143181746