继承本身就具有复杂性,在设计上并不鼓励,在可以使用其他设计方式替代的场合,例如合成(composite),往往建议别使用继承;C++ 可以多重继承,也就是子类可以同时继承多个父类,既然单一继承已经有复杂性了,可想而知地,多重继承更会急剧地增加复杂度。
限制复杂度的方式之一,是限制只能继承一个具有状态定义的父类,因为状态本身就是复杂的根源,同时继承多个具有状态定义的父类,只会令状态的管理更复杂。
来看看从〈纯虚拟函数(二)〉衍生出来的简单情境,如果今天老板突发奇想,想把海洋乐园变为海空乐园,有的东西会游泳,有的东西会飞,有的东西会游也会飞,那么现有的程序可以应付这个需求吗?
仔细想想,有的东西会飞,但这些东西的状态定义不一定是相同的,有了〈纯虚拟函数(二)〉的经验,你使用定义了Flyer
:
class Flyer {
public:
virtual void fly() = 0;
virtual ~Flyer() = default;
};
Flyer
定义了fly
方法,程序中想要飞的东西,可以继承Flyer
,,而有的东西会飞也会游,例如飞鱼,它是一种鱼,可以继承Fish
,而它也可以飞,因此同时继承了Flyer
:
class FlyingFish : public Fish, public Flyer {
public:
using Fish::Fish;
void swim() override {
cout << "飞鱼 " + this->name + " 游泳" << endl;
}
void fly() override {
cout << "飞鱼 " + this->name + " 飞翔" << endl;
}
};
在这边运用了多重继承,若要继承多个父类,只要用逗号区隔就好了,接着你想,来个超人吧!
class SuperMan : public Flyer, public Swimmer {
protected:
string colorOfunderpants;
public:
SuperMan(string colorOfunderpants) :
colorOfunderpants(colorOfunderpants) {}
string getColorOfunderpants() {
return this->colorOfunderpants;
}
void swim() override {
cout << "超人穿着 " + this->colorOfunderpants + " 内裤在游泳" << endl;
}
void fly() override {
cout << "超人穿着 " + this->colorOfunderpants + " 内裤在飞" << endl;
}
};
虽然叫超人,不过电影里的超人往往不是人,就不继承Human
了,而是继承Flyer
与Swimmer
;接下来,能游的就游,能飞的就飞吧!
...
void doSwim(Swimmer &swimmer) {
swimmer.swim();
}
void doFly(Flyer &flyer) {
flyer.fly();
}
int main() {
Anemonefish anemonefish("尼莫");
Shark shark("兰尼");
Human human("贾斯汀", "林");
Submarine submarine("黄色一号");
FlyingFish flyingFish("菲尔普斯");
SuperMan superMan("红色");
doSwim(anemonefish);
doSwim(shark);
doSwim(human);
doSwim(submarine);
doSwim(flyingFish);
doSwim(superMan);
doFly(flyingFish);
doFly(superMan);
return 0;
}
执行结果如下:
小丑鱼 尼莫 游泳
鲨鱼 兰尼 游泳
人类 贾斯汀 林 游泳
潜水艇 黄色一号 潜行
飞鱼 菲尔普斯 游泳
超人穿着 红色 内裤在游泳
飞鱼 菲尔普斯 飞翔
超人穿着 红色 内裤在飞
这是多重继承的一个简单运用:为了不同状态定义的类实例能够多态。因为继承的来源没有状态定义,只有行为规范,才令多重继承时的复杂度不致于一下难以控制。