C++ 详解多重继承和虚继承、多重继承可能出现的问题

多重继承可能会导致命名冲突和数据冗余,通过虚继承可以解决命名冲突问题。

多重继承可能会导致的问题

多重继承是从派生类从多个基类中继承而来。所以可能会出现数据冗余以及命名冲突的问题。

例如 有基类A , B、C由A继承而来,D多重继承了A和B,那么D中将会出现命名冲突的问题,因为B、C中都包含基类A 中的成员。这导致出现了菱形继承关系

解决方法1:声明出现冲突的成员变量来源于哪个类

var1是来自基类A的对象,被B、C继承了,D又多重继承了B、C,那么在定义一个D类对象,想要对var1进行赋值的时候,需要声明这个var1是来自继承的哪一个类。

1
void set_var1(int tmp) { Base2::var1 = tmp; }

解决方法2:虚继承

使用虚继承的目的:保证存在命名冲突的成员变量在派生类中只保留一份,即使间接基类中的成员在派生类中只保留一份。在菱形继承关系中,间接基类称为虚基类,直接基类和间接基类之间的继承关系称为虚继承。

实现方式:在继承方式前面加上 virtual 关键字

类的继承关系

问题:命名冲突的成员变量在派生类中只保留一份,那么所有的类中的成员变量都统一了直接?从原理角度来讲应该是这样。

详细补充一些内容:
虚继承使派生类除了继承基类成员作为自己的成员之外,内部还会有一份内存来保存哪些是基类的成员。当Derive继承Base2和Base3之后,编译器根据虚继承多出来的内存,查到Base2和Base3拥有共同的基类的成员,就不会从Base2和Base3中继承这些,而是直接从共同的基类中继承成员,也就是说,Derive直接继承base的成员,然后再继承Base2和Base3各自新增的成员。这样,Derive就不会继承两份内存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
using namespace std;

// 间接基类,即虚基类
class Base1
{
public:
int var1;
};

// 直接基类
class Base2 : virtual public Base1 // 虚继承
{
public:
int var2;
};

// 直接基类
class Base3 : virtual public Base1 // 虚继承
{
public:
int var3;
};

// 派生类
class Derive : public Base2, public Base3
{
public:
void set_var1(int tmp) { var1 = tmp; }
void set_var2(int tmp) { var2 = tmp; }
void set_var3(int tmp) { var3 = tmp; }
void set_var4(int tmp) { var4 = tmp; }

private:
int var4;
};

int main()
{
Derive d;
return 0;
}