关于多态的概念

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被赋予了TDog类型的对象。也就是说,一个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节结尾处的问题了。 抽象方法本身不能够做任何事
情,必须在子类中被重载并实现,才能够完成有意义的工作。但抽象方法的存在,相当
于为父类留下了一个接口,当程序将一个子类的对象赋予父类的变量时,父类的变量就
可以调用这个方法,当然此时它运行的是相应的子类中重载该方法的代码。如果没有这
个抽象方法,父类的变量就不能调用它,因为它不能调用一个只在子类中存在、而在父
类中不存在的方法!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值