文章目录
- 1. 为什么 C++ 有多继承,Java 没有多继承呢?
- 2. 什么是菱形继承呢?
- 3. 菱形继承产生数据冗余和二义性问题
1. 为什么 C++ 有多继承,Java 没有多继承呢?
C++ 实现多继承是为了满足某些场景的需要,但是有多继承就一定会有 菱形继承的情况,菱形继承会导致数据冗余和二义性问题,所以菱形继承需要避免,这是一个bug,所以Java为了避免菱形继承,通过单继承和接口来实现,没有多继承。
2. 什么是菱形继承呢?
- ① 如下图所示,就是一个菱形继承,注意❗:菱形继承不代表一定要满足菱形。
- ② 一个派生类同时继承自两个或多个基类,而这些基类又继承自同一个共同的基类,形成了一个菱形的继承结构。
3. 菱形继承产生数据冗余和二义性问题
数据冗余:
① 如下图所示,明明是同一个人,却存了两个名字;
② 菱形继承可能会造成重复存储相同的成员变量,增加了内存消耗;
二义性:
① 当研究生助理为学生的时候,他叫小张,当他为老师的时候,他又叫张老师,那么此时就会存在一个问题,他到底叫什么呢?
② 如果派生类继承的两个基类都有相同的函数,并且派生类中没有对这些函数进行覆盖或隐藏,那么在派生类中调用这些函数时,编译器无法确定要调用哪个版本的函数,从而导致二义性。
- 如何解决菱形继承问题的呢?
在 C++ 中,可以通过
虚继承(Virtual Inheritance)
来解决菱形继承所带来的数据冗余和二义性问题。
虚继承是一种特殊的继承方式,可以确保共同基类在派生类中只有一份实例,从而避免了数据冗余和二义性问题。
- 为了研究虚拟继承原理,我们给出了一个简化的菱形继承继承体系,再借助内存窗口观察对象成
员的模型。
#include <iostream>
using namespace std;
class A
{
public:
int _a;
};
// class B : public A
class B : virtual public A
{
public:
int _b;
};
// class C : public A
class C : virtual public A
{
public:
int _c;
};
class D : public B, public C
{
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}
- 下图是菱形虚拟继承的内存对象成员模型:这里可以分析出D对象中将A放到的了对象组成的最下
面,这个A同时属于B和C,那么B和C如何去找到公共的A呢?这里是通过了B和C的两个指针,指
向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量
可以找到下面的A。
- 下面是Person关系菱形虚拟继承的原理解释: