前言

相对而言了解了继承在构造函数和析构函数时执行的区别。
包括函数重命名时作用域区分的时候。


正文

多重继承

从生理学角度,一个儿子就一个爹。
但是子类比较特殊,它可以拥有多个父类

1
2
3
4
5
6
7
8
9
10
11
12
13
class pople{
public:
pople(){
std::cout << "pople created\n";
}
};

class wolf{
public:
wolf(){
std::cout << "wolf created\n";
}
};

当狼和人组合,产生子类狼人

1
2
3
4
5
6
class werewolf:public pople,public wolf{
public:
werewolf(){
std::cout << "werewolf created\n";
}
};

继承方式无所谓,一般都public,父类名由逗号分隔。

实例化类,能看到他是继承了两个父类,构造函数的顺序也跟我们继承时候的顺序相关。

当两个父类有相同的成员函数时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class pople{
public:
pople(){
std::cout << "pople created\n";
}
void eat(){ //eat
std::cout << "pople eat!\n";
}
};

class wolf{
public:
wolf(){
std::cout << "wolf created\n";
}
void eat(){ //eat
std::cout << "wolf eat!\n";
}
};

用父类作用域的函数是最直接的行为。

另一种就是uisng去强制解锁。但是面对重名的情况感觉还是靠作用域比较好。

不过归根到底,展现给用户的肯定是越简单越好。

那么究竟是处于哪个父类的状态时就调用哪个父类的功能,比如加个if,条件可以自己想,狼人,要么怒气拉满,要么月圆之夜什么的。

1
2
3
4
5
6
7
8
9
10
11
12
class werewolf:public pople,public wolf{
public:
werewolf(){
//std::cout << "werewolf created\n";
}
void eat(){
if (anger == 100) wolf::eat();
else pople::eat();
}
private:
unsigned short anger = 0; //怒气
};

当怒气为0的时候,还处于人类状态,行为自然就是人类的行为这很好理解。

修改怒气为100的时候,达到了变身条件,处于狼的状态,行为转化为狼的行为

1
unsigned short anger = 100;	//怒气

至于怒气怎么增加,就看想要什么样的感觉设定了,这就不讨论了。


多重继承重复

werewolf是继承自wolf和pople。倘若wolf和pople也有父类。
那么werewolf就会出现重复的问题。

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
class animal{
public:
int x;
int y;
};

class pople:public animal{
public:
pople(){
//std::cout << "pople created\n";
}
void eat(){
std::cout << "pople eat!\n";
}
};

class wolf:public animal{
public:
wolf(){
//std::cout << "wolf created\n";
}
void eat(){
std::cout << "wolf eat!\n";
}
};

class werewolf:public pople,public wolf{
public:
werewolf(){
//std::cout << "werewolf created\n";
}
void eat(){
if (anger == 100) wolf::eat();
else pople::eat();
}
private:
unsigned short anger = 100; //怒气
};

我们创建新的类animal,让wolf和pople去继承。
并且animal类中有两个成员变量x,y。

当我们给werewolf实例化对象的x和y赋值的时候就能看到问题了:

编译器提示到x不明确,为什么会不明确

随便画个草图示意。就是因为多重继承的时候,父类的父类,套娃了。重复继承了xy属性。

解决这种情况,肯定是作用域最直接,直接告诉他指向哪个区域就行了。

而且多重继承带来的问题就是内存,animal的属性被wolf和pople分别继承之后,又共同被werewolf继承,这样一来,werewolf就会有多组的x和y占用内存。

还有一种方法就是虚基类,也是跟后面虚函数有点关系。

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
class animal{
public:
int x;
int y;
};

class pople:public virtual animal{ //虚基类
public:
pople(){
//std::cout << "pople created\n";
}
void eat(){
std::cout << "pople eat!\n";
}
};

class wolf:public virtual animal{ //虚基类
public:
wolf(){
//std::cout << "wolf created\n";
}
void eat(){
std::cout << "wolf eat!\n";
}
};

class werewolf:public pople,public wolf{
public:
werewolf(){
//std::cout << "werewolf created\n";
}
void eat(){
if (anger == 100) wolf::eat();
else pople::eat();
}
private:
unsigned short anger = 100; //怒气
};

通过两组虚继承之后,测试之前的样例:

看到wolf的xy居然都变成了pople的xy设置的值,这也是virtual的好处,他会判断是否重复引用了,当子类重复继承到父类的属性的时候,就会主动忽略掉。


结语

只不过多重继承带来的组合问题,有些时候不利于解读,毕竟从小零件构造大物件,还是把大物件拆成小零件。