《多态与动态联编》PPT课件.ppt_第1页
《多态与动态联编》PPT课件.ppt_第2页
《多态与动态联编》PPT课件.ppt_第3页
《多态与动态联编》PPT课件.ppt_第4页
《多态与动态联编》PPT课件.ppt_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第11章多态与动态联编 本章教学目标 理解虚拟函数 动态多态性和动态联编地概念 了解虚拟函数和动态联编对实现动态多态地作用 理解虚拟函数地声明 定义方法和访问属性 理解纯虚拟函数和抽象类地概念 掌握纯虚拟函数和抽象类的定义方法 了解抽象类和具体类的区别 了解虚拟析构函数的概念和作用 掌握其声明和使用方法 理解动态联编的实现机理 学会使用动态多态特性 第11章多态与动态联编 11 1虚拟函数 动态多态性与动态联编11 2虚拟函数的访问属性11 3纯虚拟函数与抽象类11 4虚拟函数应用举例11 5虚拟析构函数11 6动态联编的实现机理 11 1虚拟函数 动态多态性与动态联编 虚拟函数 virtualfunction 是C 进行OOP最富魅力的特征 灵活运用虚拟函数可以构造高度抽象和重用性好的程序 例11 1虚拟函数的定义和使用 includeclassBase public virtualvoidvfun void 用关键字virtual定义虚拟函数vfun cout Basevfun n classDrv1 publicBase public voidvfun void cout Drv1vfun n classDrv2 publicBase classDrv3 publicBase public voidvfun void cout Drv3vfun n classDDrv publicDrv1 public voidvfun void cout DDrvvfun n voidmain Base vp 同一接口 多种方法 vp newBase vp vfun vp newDrv1 vp vfun vp newDrv2 vp vfun vp newDrv3 vp vfun vp newDDrv vp vfun 程序的执行结果如下 BasevfunDrv1vfunBasevfunDrv3vfunDDrvvfun 此例中 用关键字virtual在基类Base中定义了一个虚拟函数vfun 同时在派生类Drv1和Drv3以及Drv1的派生类DDrv中分别定义了一个接口完全相同的函数 可省略关键字virtual 系统自动地将其定义为virtual 但从可读性方面考虑建议不要省略virtual 但在派生类Drv2中没有定义vfun 这样做是为了对比地说明虚拟函数的用法 为了使用虚拟函数必须使用指向基类的指针 本例中 在主函数中定义了一个指向基类Base的指针vp 在C 中一个指向基类的指针可以用来指向其派生类的对象 访问非虚拟函数是编译时决定的 称为 静态联接 或 静态约束 静态装订 staticbinding 或 早期约束 earlybinding 访问虚拟函数是在程序运行时动态决定的 称为 动态联接 或 动态约束 动态装订 dynamicbinding 或 晚期约束 latelybinding 虚拟函数 基类中被关键字virtual说明并在一个或多个派生类中被重新定义的函数原型完全一致的成员函数 关于虚拟函数应注意以下几点 除虚拟析构函数外 虚拟函数要求函数原型必须完全相同 函数体可不同 否则视为重载函数 虚拟函数必须是类的成员函数 静态成员函数和构造函数除外 一般说来 外部函数不能声明为虚拟函数 友元不能声明为虚拟函数 但虚拟函数可以是另一个类的友元 析构函数可以是虚拟函数 但构造函数不能为虚拟函数 当基类中的析构函数定义为虚拟函数以后 派生类中的析构函数都自动定义为虚拟函数 很显然 派生类的析构函数与基类的析构函数是不同名的 如果想使用虚拟函数进行动态约束 则必须用指向基类的指针或引用来访问它 否则将为静态联编 使用虚拟函数的最大优点是 通过动态装订构造了一个抽象接口 提高了模块的独立性和易维护性 在C 中 利用虚拟函数和多态性 使得基类和派生类之间形成一种从抽象到具体 从一般到特殊的层次关系 在基类中我们可以声明本类和派生类都共有的函数 即一般化 抽象化 通用化 泛化 同时允许在派生类中对其中的某些或全部函数进行特殊定义 具体化 特殊化 特化 这种方法更接近于人类的思维方法 这也是虚拟函数和多态的重要性所在 11 2虚拟函数的访问属性 虚拟函数的访问属性不决定于动态联编函数的访问属性 而决定于访问语句中虚拟函数的静态访问属性 即决定于访问语句 指针变量 虚拟函数或者 引用变量 虚拟函数中指针变量或引用变量所属类中的虚拟函数的访问属性 例11 2虚拟函数的访问属性 includeclassA public virtualvoidvfun void 公有的虚拟函数 cout Avfun n classB publicA private voidvfun void coutvfun 通过指针pA调用虚拟函数vfun Bb 定义B类的对象bA 程序的执行结果如下 BvfunBvfunCvfun 在上面的程序中 定义了三个类 A派生出B B派生出C 在A B C中都定义了虚拟函数vfun 但它们的访问属性不同 在A中 vfun 定义在public段内 是公有虚拟函数 在B和C中 vfun 都定义在private段内 都是私有虚拟函数 在main 函数中第 句以及运行结果的第一行表明 虽然B类的vfun 是私有函数 但是仍然能够通过指针pA访问它 这是因为pA是指向A类的指针 而在A类中vfun 是公有函数 即虚拟函数的访问属性是由访问形式 pA vfun 的属性决定的 而不是由它实际访问的虚拟函数的属性决定的 也就是说 虚拟函数的访问属性是静态决定的 而不是动态决定的 main 函数中第 和 句也是基于同样理由 其中第 句是通过引用来访问虚拟函数 第 句还说明指向基类的指针可以访问其下两级甚至更多级派生类中的虚拟函数 main 函数中第 句以注释的形式出现是因为它们无法通过编译 其原因是访问形式 pB vfun 是私有的 因此编译时会产生 B vfun isnotaccessible B vfun 是不可访问 的错误信息 11 3纯虚拟函数与抽象类 与普通函数一样 基类中的虚拟函数一般必须用一个函数体来定义其操作 可为空 如果不作定义 可以把它声明为纯虚拟函数 purevirtualfunction 纯虚拟函数的定义格式如下 virtual返回值类型函数名 参数表 0 例如 classhuman virtualintgeneral 0 纯虚拟函数 带有一个或多个纯虚拟函数的类叫做抽象类 abstractclass 抽象类只能作为其他类的基类 因此通常把抽象类称为抽象基类 C 规定 不能建立抽象类的对象 也不能把抽象类作为函数的参数类型或返回值类型 但可以定义指向抽象类的指针和不需初始化的抽象类引用 任何由抽象类派生出来的派生类都必须重新声明它所继承的全部纯虚拟函数 不管这些纯虚拟函数在该派生类中作为普通的虚拟函数还是作为纯虚拟函数 例11 3动态多态的实现 includeclassplane 抽象类 protected doubleh b r s public virtualvoidset hb 0 纯虚拟函数virtualvoidset r 0 纯虚拟函数virtualvoidarea 0 纯虚拟函数voiddisplay cout Thearea s endl classcircle publicplane 圆 公有派生于平面 public voidset hb voidset r cout r voidarea s 3 14 r r classtriangle publicplane 三角形 也公有派生于平面 public voidset hb cout h b voidset r cout triangle endl voidarea s h b 2 classEqtriangle publictriangle 等边三角形 公有派生于三角形 public voidset hb cout b voidarea s 0 866 b b 2 voidDo plane p 多态执行函数 p set hb p set r p area p display voidmain plane p newcircle 动态创建circle类的对象Do p 调用多态执行函数 deletep p newtriangle 动态创建triangle类的对象Do p 调用多态执行函数deletep p newEqtriangle 动态创建Eqtriangle类的对象Do p 调用多态执行函数deletep 程序的执行结果如下 Inputcircle sr 10Thearea 314Inputtriangle shandb 2030triangleThearea 300Inputtheside 26triangleThearea 292 708 该程序定义了三个类 其中plane为基类 其余两个为派生类 由于plane中含有三个纯虚拟函数set hb set r 和area 因此该类是一个抽象基类 基类中的protected成员h b r和s分别为三角形的高 底边长 圆的半径和图形的面积 函数display 用来显示面积值 在派生类triangle和circle中都重新定义了基类中的三个纯虚拟函数 在triangle中函数set hb 用来设置h b的值 函数area 用来计算三角形的面积 而函数set r 在triangle中用不着 所以将其函数体定义为空 目的是main 函数中要用动态存储分配的方法来建立triangle类的对象 如果仍将set r 函数声明为纯虚拟函数或干脆将其去掉 则triangle仍为抽象基类而不能建立其动态对象 同理 circle中的set hb 也定义成函数体为空的函数 在circle中 set r 用来设置圆的半径r的值 函数area 则用来计算圆的面积 它的计算方法不同于三角形面积的计算 在主程序中定义了一个指向抽象基类的指针p 然后用动态存储分配的方法来建立类triangle的对象 用指针访问triangle的对象中的成员函数 分别设置一个三角形的参数 计算其面积并显示计算结果 最后释放triangle的对象所占用的存储空间 对于circle类亦同样处理 在这里用到了 p area 但计算的是不同形体的面积 它们的计算方法是不同的 体现出 同一接口 不同方法 的程序设计技术 11 4虚拟函数应用举例 在本小节内我们将对比地介绍非多态实现与多态实现的区别 从而说明多态实现在程序开发和维护中的作用 面是一个产品管理中的小例子 对半成品semifinished 零件component和总成assembly三种产品进行管理 程序采用链表结构 例5 4是非多态性实现 例5 5是多态性实现 11 4 1产品管理程序的非多态解例11 4由三个文件组成 在头文件exp11 4 h中定义了节点类Node和链表类chain 文件exp11 4a cpp是类方法的具体实现 exp11 4b cpp是主程序 例11 4产品管理非多态解 略 11 4 2产品管理程序的多态解例11 5由三个文件组成 在头文件exp11 5 h中定义了节点类Node和它的三个派生类semifinished component assembly以及链表类chain 文件exp11 5a cpp是类方法的具体实现 exp11 5b cpp是主程序 例11 5产品管理多态解 略 11 4 3非多态解和多态解系统的维护多态解较非多态解对系统维护提供了明显的巨大优点 为了说明这一点 假定我们要在产品种类中增加一个新的品种purchases 外购件 它的独特属性有供应商firm和单价price 对于例5 4 我们要在头文件的枚举类型中增加purchases 要增加一个新的全局结构类型 structPurcType charfirm 20 floatprice 以表示外购件的独特属性 并且要将PurcTypeu增加到无名共用体中去 以便能在节点中表示外购件的独特属性 要在exp5 4a cpp文件中的Node sets 函数体的switch语句中增加如下的case语句块 casepurchase cout u firm cout u price break 以便输入外购件的独特属性 要在chain print 函数体的switch语句中增加如下的case语句块 casepurchase coutu firmu price break 以便输出外购件的独特属性 最后 在主程序中增加如下语句 temp newNode 345678912 Tyre purchase temp sets products insert temp 以便将外购件产品轮胎 Tyre 插入到链表中 从上面的过程我们可以看出 这种维护对于一个大型系统将是相当繁琐的 其每一步都必须经过慎密的考虑 所有修改过的文件都必须重新编译 并且还必须经过严格的正确性验证 对于例5 5 我们不必修改类的定义头文件和类的实现文件 只需增加一个purchase派生类的定义文件和一个实现文件 略 多态解系统的维护具有高度的局部性和可靠性 11 5虚拟析构函数 在一个类的层次系统中 如果对象是用多态性动态分配的 那么 使用通常的析构函数来Delete这些对象就会出错 解决方法 将基类析构函数声明为虚拟析构函数 这样就会使所有派生类的析构函数自动成为虚拟析构函数 构造函数是不能定义为虚拟

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论