面向对象理论(4)-Inheritance

 继承
继承是面向对象中扩展对象的一种方法。子类通过继承父类,以获得父类的属性和方法。
我们通常称子类也为派生类,而称父类为基类。
下面的代码中,Button类就是继承关系中的基类,ImageButton类派生自Button类,于是,Button就是ImageButton类的父类(基类)。ImageButton就是Button类的一个派生类。

class  Button
{
    string text 
=   "" ;
    Rect rect 
=   null ;
    
//...
}

// C++; class ImageButton : public Button
// C#; class ImageButton : Button
// Java; class ImageButton extends Button
class  ImageButton : Button
{
    Image image 
=   new  Image();
    
//...
}


有旧,有新,有借,有蓝;在一只鞋里放一枚六便士的银币。
                                                            ----维多利亚时代的谚语

我们强调有旧,有新,也就说,为什么要继承呢?在上面的代码中我使用了C#的语法,而忽略了一些语法细节,但是Java的语法更好的说明了继承的作用,就是其目的在于扩展。
这里,ImageButton不但有了父类中的属性,比如text,也有了Button的区域,并且有了新的成员,Image对象。这是Button对象所没有的。

当然了,这并不是全部,继承也会继承父类的方法(我们暂且不去理会基类中的private方法)。

class  Button
{
    
private  String text  =   "" ;
    
private  Rect rect  =   null ;
   
    
public   void  setText(String text) {
          
this .text  =  text;
    }
}


class  ImageButton extends Button
{
    
private  Image image  =   null ;

    
public   void  setImage(Image image) {}
}
/
ImageButton button 
=   new  ImageButton();
button.setText(
" Cancel " );
button.setImage(
new  Image());


button实例,不但可以访问父类的方法setText(...),设置按钮的文本,还可以调用ImageButton类自己的方法setImage()去设置该按钮的图片。

我们还有许多派生的例子,比如说:

class  CDialog
{
}
class  MyDialog :  public  CDialog
{
}

这样,我就创建了一个自己的对话框类。

IS-A
讲述一个最重要的对象关系,is-a,用自然语言表达就是说“是一个”,“是一种”。它表达了一种正确的派生关系。
    Button button = new ImageButton();
或者,把代码写成如下的形式:
    ImageButton imageButton = new ImageButton();
    Button button = (Button)imageButton;
这份代码,表明了这样一点,一个ImageButton对象,也是一个Button对象。这种关系就像是说猫是一种动物,飞机是一种交通工具一样。这就是我们所说的is-a关系。
An ImageButton is-a Button, also.
这个关系非常重要,它将直接影响到设计,和代码的可理解性。因为继承给了我们如此简单的扩展方式,于是,滥用继承也成为了一个问题。
class B extends A
{
}
我们要思考继承的合理性,语法上成立的代码,未必是合理的代码,代码上显示B对象也是A对象。但是我们要用自然语言去解读一下,一个B对象is-a A对象嘛?这很自然嘛?很合理嘛?很通顺嘛?

当然了,也不必那么完全符合我们对自然界的认识。有很多成功的继承,虽然看起来很怪异,但是它确实是行之有效的扩展。

多继承
比如说现在的许多手机,它既是一个移动电话,也是一个iPod。那么很显然,它确实具有两个合理的is-a关系。
而,C++支持多继承,正是因为事物可能具有多种性质(这个性质并非属性的意思,你可以参考波粒二象性的深意)。

class  iPhone :  public  MobilePhone,  public  iPod
{
}

我很高兴C++支持多继承,也很高兴Apple给了这样一个合理的例子,让我觉得我没有错误地使用多继承(其实,我相信还是有很多人会站出来说这个继承关系不恰当。也许吧,但是它确实可以工作,这个很重要。)。
【1】事实上,在C++中,往往多继承,更多体现于一种技巧的使用。在后面,我们会提及这些技巧。

继承还是聚合?
C++支持多继承,而绝大多数的面向对象语言不支持这种特性,于是通常采用聚合的方式来实现对象的扩展,这是一个非常好的习惯。

class  iPhone extends  MobilePhone
{
    
private  iPod o  =   new  iPod();
}


然而,聚合不能取代继承。
聚合引发的对象关系是has-a,而继承(C++中特指public继承)引发的对象关系是is-a。从设计的角度来讲,这种差别很大,尽管我们可以用聚合实现继承,但是在我们需要is-a关系的时候,聚合就不那么方便了。
但是,我们这样写,是被鼓励的。而且对于Java和C#来说,这样似乎是唯一的做法(其实是有其他的做法的,但是那已经不是语法层次上面可以解决的问题了。【2】)。

多继承还是单继承?
尽管C++支持多继承,我们也不能滥用多继承,因为软件工程证明了,大多数的多继承是有害的,尽管许多C++的类库使用了多继承的方式,但是如果你没有想清楚,就不要设计出这样的继承关系。尽量用聚合来代替继承关系。


【2】. 我们会在后面讨论的。那是一个模式的使用问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值