心寄笔端 附庸风雅

甘草的技术博客

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
继承
继承是面向对象中扩展对象的一种方法。子类通过继承父类,以获得父类的属性和方法。
我们通常称子类也为派生类,而称父类为基类。
下面的代码中,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】. 我们会在后面讨论的。那是一个模式的使用问题。
posted on 2008-06-13 15:20  甘草  阅读(521)  评论(0编辑  收藏  举报
Baidu
Google
心寄笔端
TEST
以后我会加上Power By的,先别介意