面向对象理论之-多态

来源:计算机等级考试    发布时间:2012-08-28    计算机等级考试视频    评论

  多态是面向对象理论中的重要概念之一,从而也成为现代程序设计语言的一个主要特性,从应用角度来说,多态是构建高灵活性低耦合度的现代应用程序架构所不可忽缺的能力。从概念的角度来说,多态使得程序员可以不必关心某个对象的具体类型,就可以使用这个对象的“某一部分”功能。这个“某一部分”功能可以用基类来呈现,也可以用接口来呈现。后者显得更为重要——接口是使程序具有可扩展性的重要特性,而接口的实现依赖于语言对多态的实现,或者干脆就象征着语言对多态的实现。
  本文并不大算赘述多态的应用,因为其应用实在俯拾皆是,其概念理论也早已完善。这里,我们打算从实现的角度来看一看一门语言在其多态特性的背后做了些什么——知其所以然,使用时方能游刃有余。
  或许你在学习一门语言的时候,曾经对多态的特性很迷惑,虽然教科书上所讲的非常简单,也非常明了——正如它的原本理念一样,但是你也想知道语言(编译器)在背后都干了些什么,为什么一个派生类对象就可以被当作其基类对象来使用?用指向派生类对象的基类指针调用虚函数时凭什么能够精确的到达正确的函数?类的内部是如何布局的?
  我们这样考虑:假设语言不支持多态,而我们又必须实现多态,我们可以怎么做?
  多态的雏形:
  class B
  {
  public:
  int flag; //为表示简洁,0代表基类,1代表派生类
  void f(){cout<<”in B::f()”;} //非虚函数
  };
  class D:public B
  {
  public:
  void f(){cout<<”in D::f()”;} //非虚函数
  };
  void call_virtual(B* pb)
  {
  if(pb->flag==0) //如果是基类,则直接调用f
  pb->f(); //调用的是基类的f
  else //如果是派生类,则强制转化为派生类指针再调用f
  (D*)pb->f(); //调用的是派生类的f
  }
  这样,可以正好符合“根据具体的对象类型调用相应的函数”的理念。但是这个原始方案有一些缺点:;例如,分发“虚函数”的代码要自己书写,不够优雅,不具有可扩展性(当继承体系扩大时,这堆代码将变得臃肿无比),不具有封闭性(如果加入了一个新的派生类,则“虚函数”调用的代码必须作改动,然而如果恰巧这个调用是无法改动的(例如,库函数),则意味着,一个用户加入的派生类将无法兼容于那个库函数)等等。结果就是——这个方案不具有通用性。
  但是,这个方案能够说明一些本质性的问题:flag数据成员用于标识对象所属的具体类型,从而调用者可以根据它来确定到底调用哪个函数。但是,可不可以不必“知道”对象的具体类型就能够调用正确的函数呢?可以,改进的方案如下:
  class B
  {
  public:
  void (*f)(); //函数指针,派生类对象可以通过给它重新赋值来改变对象的行为
  };
  class D:public B
  {};
  void call_virtual(B* pb)
  {
  (*(pb->f))(); //间接调用f所指的函数
  }
  void B_Mem()
  {
  cout<<”I am B”;
  }
  void D_Mem()
  {
  cout<<”I am D”;
  }
  int main()
  {
  B b;
  b.f=&B_Mem; //B_Mem代表B的“虚函数”
  D d;
  d.f=&D_Mem; //以D_Mem来覆盖(override)B的虚函数
  call_virtual(&b); //输出“I am B”
  call_virtual(&d); //输出“I am D”
  }

上一页123下一页

视频学习

我考网版权与免责声明

① 凡本网注明稿件来源为"原创"的所有文字、图片和音视频稿件,版权均属本网所有。任何媒体、网站或个人转载、链接转贴或以其他方式复制发表时必须注明"稿件来源:我考网",违者本网将依法追究责任;

② 本网部分稿件来源于网络,任何单位或个人认为我考网发布的内容可能涉嫌侵犯其合法权益,应该及时向我考网书面反馈,并提供身份证明、权属证明及详细侵权情况证明,我考网在收到上述法律文件后,将会尽快移除被控侵权内容。

最近更新

社区交流

考试问答