发信人: atong (sut), 信区: BorlandDev
标  题: 深入delphi编程(转4)
发信站: 哈工大紫丁香 (Wed Jul  3 20:04:41 2002) , 转信

1.3 多态
  
  多态相对来说比较复杂一点。不过不要担心,它的内容比较少,而且如果以前的知识
掌握得比较稳固的话,多态的概念是水到渠成的。
  先来讨论一下类型的兼容性问题。下面是一个例子:
  
  type
  tanimal = class
  procedure voice;virtual;
  ...
  end;
  
  tdog = class(tanimal)
  procedure voice;override;
  ...
  end;
  
  implementation
  
  procedure tanimal.voice;virtual;
  begin
  playsound('anim.wav',0,snd_async);
  end;
  
  procedure tdog.voice;virtual;
  begin
  playsound('dog.wav',0,snd_async);
  end;
  
  tdog类继承了tanimal类,并重载了其中的voice方法。playsound是一个win api函数
,可以播放指定的wav文件。(这个函数的定义在mmsystem.pas文件中可以找到。)
  先看这段代码:
  
  var
  myanimal1, myanimal2: tanimal;
  begin
  myanimal1 := tanimal.create;
  myanimal2 := tdog.create;
  ...
  
  在实现部分的第一行中,建立了一个tanimal类型的对象,并将其赋予tanimal类型的
变量myanimal1。这是很正常的事。但在第二行中,建立了一个tdog类型的对象,并将其赋
予了tanimal类型的变量myanimal2。这看上去令人吃惊,但这些代码是完全合法的。
  众所周知,pascal以及object pascal是一种类型定义严格的语言,你不能将某个类型
的值赋予不同类型的变量,例如将一个整型值赋予布尔型变量,将会导致出错。但是,这
个规则在涉及到oop领域时,出现了一个重要的例外,那就是:可以将一个子类的值赋予一
个父类类型的变量。但倒过来却是不行的,一个父类的值决不能赋予一个子类类型的变量

  如果将这个原则放到现实世界中,那就很容易理解了:“狗”继承自“动物”,因为
狗也是一种动物。所以可以将一个“狗”类型的值赋予“动物”类型的变量,因为“狗”
具有“动物”的一切特征。但反过来,“动物”不具有“狗”的所有特征,因此反向赋值
是不行的。
  那么,这种兼容规则在编程中究竟有什么用处呢?
  请注意下面这段代码:
  
  var
  myanimal1, myanimal2: tanimal;
  begin
  myanimal1 := tanimal.create;
  myanimal2 := tdog.create;
  myanimal1.sound;
  myanimal2.sound;
  ...
  
  myanimal1和myanimal2都是tanimal的变量,而且都调用了sound方法。但是,执行的
结果是完全不同的:前者执行的是tanimal.voice的代码,而后者执行的是tdog.voice的代
码!其原因很简单,因为myanimal1被赋予了tanimal类型的对象,而myanimal2被赋予了t
dog类型的对象。也就是说,一个tanimal类型的变量,当它调用sound方法时,所执行的代
码是不确定的:可能执行tanimal.voice的代码,也可能执行的是tdog.voice的代码,取决
于它当时引用的是一个什么样的对象。
  再看:
  
  myanimal1 := tanimal.create;
  myanimal1.sound;
  myanimal1.free;
  myanimal1 := tdog.create;
  myanimal1.sound;
  ...
  
  同一个变量myanimal1,在第一次调用sound方法时,执行的是tanimal.voice的代码,
在第二次时执行的是tdog.voice的代码。myanimal1.sound这行代码不需要变化,程序可以
根据不同的情况赋予该变量不同的对象,从而使它执行不同的代码。这就是多态的定义。

  这个非常重要的特点大大地增加了代码的可复用性。如前所述,只需要简单地写下一
行代码,就可以让程序执行不同的功能,因为这个虚拟方法同tanimal的任何派生类都是兼
容的,甚至连那些还没有编写出来的类也是一样。而程序员并不需要了解这些派生类的细
节。利用多态性写出来代码,还具有简洁和维护性好的特点。
  现在我们可以回到本文的1.2节结尾处的问题了。抽象方法本身不能够做任何事情,必
须在子类中被重载并实现,才能够完成有意义的工作。但抽象方法的存在,相当于为父类
留下了一个接口,当程序将一个子类的对象赋予父类的变量时,父类的变量就可以调用这
个方法,当然此时它运行的是相应的子类中重载该方法的代码。如果没有这个抽象方法,
父类的变量就不能调用它,因为它不能调用一个只在子类中存在、而在父类中不存在的方
法!
  
  关于oop的介绍就到此这止。在以上这些篇幅里,介绍的只是oop最基本的一些概念,
让读者对oop有一定的系统认识,也为下文的讨论打好基础 。更多、更深入的东西等待着
你自己去发掘。
  本文已经多次强调oop的重要性,这里还要强调一次:对oop的掌握程度,在某种意义
上决定着你对delphi世界的理解能力。
  
  

--

※ 来源:.哈工大紫丁香 http://bbs.hit.edu.cn [FROM: 202.118.239.3]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.422毫秒