.首先看见标题是不是有点懵,感觉很高大尚唬人的一个名字is-a,但是下面我就来解释一下什么是is-a关系,看完本篇博客后你就觉得其实原来是个“挫逼”!
1.public继承意味着is-a的关系,简单来讲is-a的关系就是:适用于基类的每一件事情一定也适用于public继承的派生类身上,因为每个派生类也都是一个基类对象。
在基类可以派上用场的任何地方,派生类一样可以派上用场,因为每个派生类对象都是一种基类对象,反之则不成立!
下面我用代码说明一下is-a的关系
class person{};
class student :public person{};//因为是公有继承满足is-a的关系
void eat(const person& p);//需要person(基类)的函数
void study(const student& s);//需要student(派生类)的函数
person p;
student s;
//下面开始阐述is-a的特性
eat(p);//正确
eat(s);//正确,s是学生,学生是人,基类可以用的地方派生类也可以
study(s);//正确
study(p);//错误,p不是学生,即反之不行原则
//这就是典型的一种is-a的关系
虽然说is-a之间的关系听起来比较简单,但是有时候也会误导你
比如1:企鹅是鸟,鸟会飞,如果企鹅类继承鸟类,可是企鹅不会飞,与现实矛盾。
class bird
{
void fly(){};
};
class Penguin :public bird
{};//按照这么继承,企鹅就会飞了,与现实中矛盾
这就需要我们自己做一定的改造了
改造方法1:
class bird{};
class Flybird :public bird
{
virtual void fly(){};
};//会飞的鸟让他飞
class Penguin :public bird
{};//按照这么继承,就解决了上面的问题
但是可能程序并不关系你会飞不会飞,你因为会不会飞而刻意设计出这种多继承,显得偏离了设计的重点没有必要,所以还是双clss继承的设计更好一定,因此有人又想出了一种双class继承体系上使其符合现实,代码如下:
void error(const std::string& msg);//报错函数
class bird
{
void fly(){};
};
class Penguin :public bird
{
virtual void fly()
{
error("企鹅不会飞这是个错误");//如果试图让企鹅飞代码会在这里报错
}
};
上面的代码满足双class继承,他是在你试图让企鹅飞的时候产生一个错误,从而使满足企鹅不会飞这一事实符合现实,但是这里是运行期间才会产生错误。
有句话说“好的接口可以防止无效的代码编译通过"但是上面的设计貌似不符合这个,他会产生没有用的报错代码,所以我们应该让编译器在编译器间就拒绝企鹅会飞这个问题,而不是在运行期间才拒绝,所以就有了下面的这种改造,
class bird
{};
class Penguin :public bird
{};
这样只要你试图让企鹅飞他就会在编译期间出错。
上面的例子只是想说明,is-a的关系一定要慎重考虑设计,不要被误导。