在前面的例子中,派生类都只有一个基类,称为单继承。除此之外,C++也支持多继承,即一个派生类可以有两个或多个基类。
多继承容易让代码逻辑复杂、思路混乱,一直备受争议,中小型项目中较少使用,后来的 Java、C#、PHP 等干脆取消了多继承。想快速学习C++的读者可以不必细读。
多继承的语法也很简单,将多个基类用逗号隔开即可。例如已声明了类A、类B和类C,那么可以这样来声明派生类D:
class D: public A, private B, protected C{
//类D新增加的成员
}
D是多继承的派生类,它以共有的方式继承A类,以私有的方式继承B类,以保护的方式继承C类。D根据不同的继承方式获取A、B、C中的成员,确定各基类的成员在派生类中的访问权限。
多继承下的构造函数
多继承派生类的构造函数和单继承类基本相同,只是要包含多个基类构造函数。如:
D类构造函数名(总参数表列): A构造函数(实参表列), B类构造函数(实参表列), C类构造函数(实参表列){
新增成员初始化语句
}
各基类的排列顺序任意。
派生类构造函数的执行顺序同样为:先调用基类的构造函数,再调用派生类构造函数。基类构造函数的调用顺序是按照声明派生类时基类出现的顺序。
下面的定义了两个基类,BaseA类和BaseB类,然后用多继承的方式派生出Sub类。
#include <iostream>
using namespace std;
//基类
class BaseA{
protected:
int a;
int b;
public:
BaseA(int, int);
};
BaseA::BaseA(int a, int b): a(a), b(b){}
//基类
class BaseB{
protected:
int c;
int d;
public:
BaseB(int, int);
};
BaseB::BaseB(int c, int d): c(c), d(d){}
//派生类
class Sub: public BaseA, public BaseB{
private:
int e;
public:
Sub(int, int, int, int, int);
void display();
};
Sub::Sub(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), e(e){}
void Sub::display(){
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
cout<<"c="<<c<<endl;
cout<<"d="<<d<<endl;
cout<<"e="<<e<<endl;
}
int main(){
(new Sub(, , , , )) -> display();
return ;
}
从基类BaseA和BaseB继承来的成员变量,在 Sub::display() 中都可以访问。
命名冲突
当两个基类中有同名的成员时,就会产生命名冲突,这时不能直接访问该成员,需要加上类名和域解析符。
假如在基类BaseA和BaseB中都有成员函数 display(),那么下面的语句是错误的:
Sub obj;
obj.display();
由于BaseA和BaseB中都有display(),系统将无法判定到底要调用哪一个类的函数,所以报错。
应该像下面这样加上类名和域解析符:
Sub obj;
obj.BaseA::display();
obj.BaseB::display();
通过这个举例可以发现:在多重继承时,从不同的基类中会继承一些重复的数据。如果有多个基类,问题会更突出,所以在设计派生类时要细致考虑其数据成员,尽量减少数据冗余。