会计考友 发表于 2012-8-2 09:08:23

2012年软件水平考试软件设计师重点解析之浅谈多态

多态性,这个面向对象编程规模的焦点概念,自己的内容博上将湛,要以一文说清嚣张其实是不太可能。加之作者本人也还在不竭进修中,水平有限。是以本文只能描一下多态的轮廓,使读者能够体味个概略。
  首先,什么是多态(Polymorphisn)?按字面的意思就是“多种外蟹羟车ケ。我手头的书膳缦慊有找到一个多态的理论性的概念的描述。暂且引用一下Charlie Calverts的对多态的描述吧--多态性是承诺你将父对象设置成为和一个或更多的他的子对象相等的手艺,赋值之后,父对象就可以按照当前赋值给它的子对象的特征以分歧的体例运作。简单的说,就是一句话:承诺将子类类型的指针赋值给父类类型的指针。多态性在Object Pascal和C++中都是经由过程虚函数(Virtual Function) 实现的。
  好,接着是“虚函数”(或者是“虚体例”)。虚函数就是承诺被其子类从头界说的成员函数。而子类从头定寄父类虚函数的做法,称为“笼盖”(override),或者称为“重写”。
  这里有一个初学者经常同化的概念。笼盖(override)和重载(overload)。膳缦沔说了,笼盖是指子类从头定寄父类的虚函数的做法。而重载,是只匾舻存在多个同名函数,而这些函数的参数表分歧(或许参数个数分歧,或许参数类型分歧,或许两者都分歧)。其实,重载的概念并不属于“面向对象编程”,重载的实现是:编译器按照函数分歧的参数表,对同名函数的名称做润色,然后这些同名函数就成了分歧的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过润色后的函数名称可能是这样的:int_func、str_func。对于这两个函数的挪用,在编译器间就已经确定了,是静态的(记住:是静态)。也就是说,它们的地址在编译期就绑定了(早绑定),是以,重载和多态无关!真正和多态相关的是“笼盖”。当子类从头界说了父类的虚函数后,父类指针按照赋给它的分歧的子类指针,动态(记住:是动态!)的挪用属于子类的该函数,这样的函数挪用在编译时代是无法确定的(挪用的子类的虚函数的地址无法给出)。
  是以,这样的函数地址是在运行期绑定的(晚邦定)。结论就是:重载只是一种说话特征,与多态无关,与面向对象也无关!
  引用一句BrUCe Eckel的话:“不要犯傻,假如它不是晚邦定,它就不是多态。”
  那么,多态的浸染是什么呢?我们知道,封装可以潜匿实现细节,使得代码模块化;继续可以扩展已存在的代码模块(类);它们的目的都是为了--代码重用。而多态则是为了实现另一个目的--接口重用!而且现实往往是,要有用重用代码很难,而真正最具有价值的重用是接口重用,因为“接口是公司最有价值的资本。设计接口比用一堆类来实现这个接口更费时刻。而且接口需要破耗更昂贵的人力的时刻。”
  其实,继续的为重用代码而存在的理由已经越来越亏弱,因为“组合”可以很好的庖代继续的扩揭示有代码的功能,而且“组合”的默示更好(至少可以防止“类爆炸”)。是以笔者小我认为,继续的存在很大水平上是作为“多态”的基本而非扩揭示有代码的体例了。 进入谈判组谈判。
  什么是接口重用?我们举一个简单的例子,假设我们有一个描述飞机的基类(Object Pascal说话描述,下同):
  type
  plane = class
  public
  PRocedure fly(); virtual; abstract; //起飞纯虚函数
  procedure land(); virtual; abstract; //着陆纯虚函数
  function modal() : string; virtual; abstract; //查寻型号纯虚函数

会计考友 发表于 2012-8-2 09:08:24

2012年软件水平考试软件设计师重点解析之浅谈多态

  end;
  然后,我们从plane派生出两个子类,直升机(copter)和喷气式飞机(jet):
  copter = class(plane)
  private
  fModal : String;
  public
  constructor Create();
  destructor Destroy(); override;
  procedure fly(); override;
  procedure land(); override;
  function modal() : string; override;
  end;
  jet = class(plane)
  private
  fModal : String;
  public
  constructor Create();
  destructor Destroy(); override;
  procedure fly(); override;
  procedure land(); override;
  function modal() : string; override;
  end;
  此刻,我们要完成一个飞机节制系统,有一个全局的函数 plane_fly,它负责让传递给它的飞机起飞,那么,只需要这样:
  procedure plane_fly(const pplane : plane);
  begin
  pplane.fly();
  end;
  就可以让所有传给它的飞机(plane的子类对象)正常起飞!不管是直升机仍是喷气机,甚至是此刻还不存在的,往后会增添的飞碟。因为,每个子类都已经界说了自己的起飞体例。
  可以看到 plane_fly函数接管参数的是 plane类对象引用,而现实传递给它的都是 plane的子类对象,此刻回忆一下开首所描述的“多态”:多态性是承诺你将父对象设置成为和一个或更多的他的子对象相等的手艺,赋值之后,父对象就可以按照当前赋值给它的子对象的特征以分歧的体例运作。
  很显然,parent = child; 就是多态的本色!因为直升机“是一种”飞机,喷气机也“是一种”飞机,是以,所有对飞机的操作,都可以对它们操作,此时,飞机类就作为一种接口。
  多态的素质就是将子类类型的指针赋值给父类类型的指针(在OP中是引用),只要这样的赋值发生了,多态也就发生了,因为实施了“向上映射”。
  应用多态的例子很是普遍,在Delphi的VCL类库中,最典型的就是:TObject类有一个虚拟的Destroy虚构函数和一个非虚拟的Free函数。Free函数中是挪用Destroy的。是以,当我们对任何对象(都是TObject的子类对象)挪用 .Free();之后,城市执行 TObject.Free();,它会挪用我们所使用的对象的析构函数 Destroy();。这就保证了任何类型的对象都可以正确地被析构。   多态性作为面向对象最主要的特征,本文所提不外是牛之一毛,还有良多内容,期待巨匠来挖掘。
页: [1]
查看完整版本: 2012年软件水平考试软件设计师重点解析之浅谈多态