条款32、确定你的public继承塑模出is-a关系

	bublic继承意味着“is-a”关系。即一个D类对象(Derived)同时也是一个B类对象(Base)。D is-a B。反之则不成立。B相比D更一般化,而D相对B更特殊化。
考虑如下:
class Person {…};
class student: public Person{…};

承上,C+中任何函数期望获得类型Person(指针或引用)的实参,也愿意接受Student对象(指或引)、
void eat(const person& p);   //通用行为
void study(const student& s);  //学生专属行为
person p;
student s;
eat(p);   //ok
eat(s);   //ok   学生也会eat
study(s);  //ok
study(p);  //错误,p不是学生

上述论点只能public继承才成立。private继承意义完全不同。
public继承和is-a之间的等价关系看起来简单,实则不然。如下鸟和企鹅的例子。
class Bird
{
public:
virtuan void fly();  //鸟可以飞
};
clas Penguin:public Bird
{…..};  //企鹅是一种鸟

我们成了语言不严谨的牺牲品,因为前提是并不是所有的鸟都会飞。
应用以下方法模拟出较佳的真实性。
class Bird
{
….  //没有声明fly函数
};
class flyBird : public Bird
{
public:
virtual void fly();
….
};
class Penguin: public Bird
{
…  //没有声明fly函数.
};

虽然这样,但我们仍然未能处理好这事情,因为有些系统并不关心会飞与否的问题,这样说明了一个事实,不存在一个“适用于所有软件的设计”。
另一种思想:所有鸟会飞,企鹅是鸟,但不会飞。重新定义fly,令其产生一个运行时错误
void error(const std::string& msg); //定义于其他某处
class Penguin:public Bird
{
public:
virtual void fly(){error(“attempt to fly”);}
…
};

这里并不是说其不会飞,而是其会飞是一种错误。这是在运行期间检测出的错误。
考虑另一种思路,即“不会飞”,不可以为其定义fly函数
class Bird
{
….  //没有声明fly函数
};
class Penguin: public Bird
{
…  //没有声明fly函数.
};

现在,当试图飞时:
Penguin p;
p.fly(); //编译器会报错误

这和上一种思想的不同之处是,第一种方法在编译期间对p.fly不会发生错误,TK18说过,好的接口可以不让无效代码通过编译,因此对比我们应该采取第二种方式 ,即在编译期间就拒绝无效代码
 
再考虑以下简单的公有继承,正方形public继承至矩形。我们都知道正方形是矩形,反之不然。
class Rectangle{
public:
virtual void setH{int newH};
virtual void setW{int newW};
virtual int height() const;  //返回当前值
virtual int width() const;
…
};
void makeBig(Rectangle& r)  //增加r的面积
{
int oldH=r.height();
r.setW(r.width()+10);  //r的宽度加上0
assert(oldH==r.height()); //判断r高是否改变
}

显然,上述asser结果永远为真。因为r的高未曾改变过
现在考虑下述代码,正方公有继承矩形。则正方形被视为矩形
class Square:public Rectangle{…};
Square s;
assert(s.width()==s.height()); //真
makeBig(s);//public,s is-a矩形 可以增加其面积
assert(s.width()==s.height());

很明显,按理第二个assert应该为真,但其却不同了(注意传递的是引用)
public主张的事情:
施行于基类对象的事情也能施行于派生类上,但本例矩形的方法明显不适用于正方。就如我们学过的:代码通过编译并不表示就可以正确运作。
is-a并不是唯一存在的类之间的关系。另外的有has-a(有一个)和is-implemented-in-terms-of(根据某物实现出),将这些作为is-a都是错误的。所以应该确实了解这些类之间的相互关系并塑造他们。

	需要记住的:
	1、public继承意味着is-a。适用于base的也适用于derived.因为每个派生类对象也是一个基类对象。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值