在c++中一个类可以从多个基类中派生(即可以有多个父类),这就是多继承。多继承的方式主要有两种:
1. 简单版本

类C会同时拥有类A和类B的特性(属性和方法,也就是两个类的所有成员)。这种方式很简单这里就不多说,主要讲下面这种方式。
2. 复杂版本

同样的,这个结构中类C也会同时拥有类A和类B的特性,但这就会有一个问题,类B1和B2都继承自A,那么类C的对象会同时包含两个A的对象。这样就会带来很多歧义性。
我们看一个典型的例子“沙发-床”:

类的关系图
代码:
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Furniture
{
public:
Furniture(void) : m_weight(0){}
Furniture(double weight) : m_weight(weight){}
~Furniture(void){}
double GetWeight() const { return m_weight; }
void SetWeight(double val) { m_weight = val; }
private:
double m_weight;
};
class Bed : public Furniture
{
public:
Bed() : Furniture(), m_second(0) {}
Bed(double weight, int second) : Furniture(weight), m_second(second){}
void Sleep(int second)
{
m_second = second;
cout << "休息" << m_second << "秒..."<< endl;
}
private:
int m_second;
};
class Sofa : public Furniture
{
public:
Sofa() : Furniture() {}
Sofa(double weight) : Furniture(weight){}
void WatchTV(string programme)
{
cout << "正在看" << programme << "节目..." << endl;
}
};
class SleepSofa : public Bed, public Sofa
{
public:
SleepSofa() : Bed(), Sofa() {}
SleepSofa(double weight, int second) : Bed(weight, second), Sofa(weight) {}
void FoldOut()
{
cout << "展开沙发当床用." << endl;
Sleep(360);
}
};
- 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
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
SleepSofa类继承自Bed和Sofa两个类,因此,SleepSofa类拥有这两个类的特性,但在实际编码中会存在如下几个问题。
1.SleepSofa类该如何定义?
Class SleepSofa : public Bed, public Sofa
{
…
}
- 1
- 2
- 3
- 4
构造顺序为:Bed sofa sleepsofa (也就是书写的顺序)
2.Bed和Sofa类都继承自Furniture,都有Weight属性也都有GetWeight和SetWeight方法,在SleepSofa类中使用这些属性和方法时,如何确定调用的是哪个类的成员?
我们看一下测试样例:
void Test()
{
SleepSofa sleepSofa;
sleepSofa.SetWeight(55);
double weight = sleepSofa.GetWeight();
}
- 1
- 2
- 3
- 4
- 5
- 6
这时会有以下错误:
.cpp(76): error C3861: ‘SetWeight’: identifier not found
error C2385: ambiguous access of ‘GetWeight’
就是说SetWeight和GetWeight是有歧义的。
解决方法:
(1). 可以使用完全限定名(即加上类的作用域)的方式,比如:
SleepSofa sleepSofa;
sleepSofa.Bed::SetWeight(55);
sleepSofa.Sofa::SetWeight(80);
- 1
- 2
- 3
这时可以看到sleepSofa对象有两个Furniture对象。如下:

(2). 虚继承
倘若,我们定义一个SleepSofa对象,让我们分析一下它的构造过程:它会构造Bed类和Sofa类,但Bed类和Sofa类都有一个父类,因此Furniture类被构造了两次,这是不合理的,因此,我们引入了虚继承的概念。
class Furniture{……};
class Bed : virtual public Furniture{……}; // 这里我们使用虚继承
class Sofa : virtual public Furniture{……};// 这里我们使用虚继承
class SleepSofa : public Bed, public Sofa {……};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
这样,Furniture类就只会构造一次,sleepSofa对象只会包含一个Furniture对象。
我们看一下测试样例:
SleepSofa sleepSofa;
sleepSofa.SetWeight(80);
- 1
- 2
这时我们Debug模式可以看到SleepSofa的m_weight值都是80。

这里虽然显示着两个Furniture对象,但其实指向的是同一个对象。我们可以看看它们的地址都是一样的。

总结
- 在程序设计中最好不要出现多继承,要有也是继承多个作为接口使用抽象类(只声明需要的功能,没有具体的实现)。因为出现一般的多继承本身就是一种不好的面向对象程序设计。
- 在出现版本2的多继承时使用虚继承的方式。