以C++进行面向对象编程,有一个重要的规则,public继承意味着是is-a关系,所谓is-a就是一种 的意思。比如我们用Person为基类,Student为派生类实现public继承。每个Student都是Person,但是每个Person不一定都是Student。在继承体系中,任何函数如果愿意接受一个Person的实参,那么也愿意接受一个Student的对象。
如:void eat(const Person& p);//可以接受Student,反过来就不行了。
另外一个例子:
class Bird
{
public:
virtual void fly(); //鸟可以飞
...
};
class Penguin:public Bird //企鹅是一种鸟
{
...
};
但是这里企鹅是不能够飞的呀!所以这不是is-a的关系!改进下:
class Bird
{
public:
...
};
class FlyingBird:public Bird
{
public:
virtual void fly();
....
};
class Penguin:public Bird //企鹅是一种鸟
{
...
};
这个继承体系更能够反应出真实性。但是我们并不能够完全处理好这些事情,软件的设计要根据你的需求来定。另外的方法:
void error(const std::string& msg);
class Penguin:public Bird
{
public:
virtual void fly(){ error("Attempt to make a Penguin fly!");}
....
};
这样做如果fly的话会导致运行期间的错误,但是我们希望编译期间出错。书中写到子类父类都不声明这个fly可以编译出错,但是我觉得过于牵强,你父类都没有声明这个函数,那么继承体系都也就不存在这个fly行为了,还谈什么客户会调用呢。
书中另外一个例子是矩形和正方形的继承设计:
class Rect
{
public:
virtual void setHeigh(int newH);
virtual void setWidth(int setW);
virtual int height() const;
virtual int width() const;
.....
};
void makeBigger(Rect& r)
{
int oldH = r.height();
r.setWidth(r.width()+10);
assert(r.height()==oldH);
}
很明显assert为真,因为height没有改变
现在继承;
class Sq;public Rect{.........};
Sq s;
....
assert(s.width()==s.height());对于所有的正方形为真
makeBigger(s);
assert(s.width()==s.height());
第二个assert也肯定为真。因为正方形的高度宽度必须相等
但是实际上这里是有问题的。make之前相等,make函数内s的宽度改变了 实际上他们根本就不相等。
public继承要求能够使用与基类的东西也可以用于派生类。但是这里是不行的,所以不符合public继承。