面向对象技术第五章_第1页
面向对象技术第五章_第2页
面向对象技术第五章_第3页
面向对象技术第五章_第4页
面向对象技术第五章_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

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

文档简介

1、第5章运行时的多态性和抽象类第第5 5章章 运行时的多态性和抽象类运行时的多态性和抽象类5.1 面向对象的重要特征:多态性面向对象的重要特征:多态性 5.2 运行时的多态性运行时的多态性 5.3 虚函数虚函数 5.4 纯虚函数与抽象类纯虚函数与抽象类 第5章运行时的多态性和抽象类5.1 面向对象的重要特征:多态性面向对象的重要特征:多态性多态性多态性(polymorphism)是面向对象程序设计的又一个重是面向对象程序设计的又一个重要特性。要特性。p 多态性体现了多态性体现了不同层次的类以及一个类的内部,类的同名成员函数之间的关系p多态性多态性提供了程序设计更大的灵活性提供了程序设计更大的灵活

2、性p多态性多态性可以降低程序的复杂性可以降低程序的复杂性p多态性多态性可以设计与实现一个易于扩展的系统可以设计与实现一个易于扩展的系统第5章运行时的多态性和抽象类 多态性多态性:就是不同对象收到相同的消息时,产生不同的动作。 通俗地说,多态性是指用一个名字定义不同的函数,这些函数执行不同但又类似的操作,即用同样的接口访问功能不同的函数,从而实现“一个接口,多种方法一个接口,多种方法”例例1:汉字里的:汉字里的“开开”例例2:狗的嗅觉:狗的嗅觉例例3:一个父亲,不同儿子:一个父亲,不同儿子5.1.1 多态性概述多态性概述第5章运行时的多态性和抽象类5.1.2 面向对象三大机制面向对象三大机制第5

3、章运行时的多态性和抽象类多态性可以分为:多态性可以分为:l 重载多态重载多态l 强制多态强制多态l 参数多态参数多态l 包含多态包含多态5.1.3 多态性的分类多态性的分类第5章运行时的多态性和抽象类 重载多态重载多态 专用多态专用多态 强制多态强制多态多态多态 参数多态参数多态 通用多态通用多态 包含多态包含多态多态性分类示意图多态性分类示意图第5章运行时的多态性和抽象类u 强制多态强制多态-类型转换类型转换一一系统预定义类型:系统预定义类型:两种转换:隐式和显式两种转换:隐式和显式1、隐式类型转换、隐式类型转换规则:规则:(1)在附值表达式在附值表达式A=B时,将时,将B值转换成值转换成A

4、的类型,然后赋值的类型,然后赋值#include iostream.hvoid main() int i; float f=3.333; i=f; coutfendl; coutiendl;第5章运行时的多态性和抽象类u 强制多态强制多态-类型转换类型转换一一系统预定义类型:系统预定义类型:两种转换:隐式和显式两种转换:隐式和显式1、隐式类型转换、隐式类型转换规则:规则:(2)当两个操作对象不一致时,将级别低的自动转换成高的,当两个操作对象不一致时,将级别低的自动转换成高的,然后运算然后运算#include iostream.hvoid main() int i=1; float f=3.3;

5、 couti+fendl; 第5章运行时的多态性和抽象类u 强制多态强制多态-类型转换类型转换2、显式类型转换、显式类型转换规则:规则:(1)(1)强制转换法强制转换法 (类型名)表达式(类型名)表达式 cout(float)(i+jcout(float)(i+j););(2)(2)函数法函数法 coutfloat(i+jcoutfloat(i+j););第5章运行时的多态性和抽象类u 强制多态强制多态-类型转换类型转换二二类类型与系统预定义类类型与系统预定义三种方式:构造函数、类型转换函数、运算符重载三种方式:构造函数、类型转换函数、运算符重载1、构造函数、构造函数规则:规则:(1)只能将参

6、数类型向类类型转换,只能将参数类型向类类型转换,反之不行反之不行#include iostream.hclass example private: int num; public: example(int);void print();example:example(int n) num=n; coutIntializing with:numendl;第5章运行时的多态性和抽象类void example:print()coutnum=numendl; void main() example X=example(3); X.print(); cout-n; example Y=6; Y.print

7、(); 第5章运行时的多态性和抽象类u 强制多态强制多态-类型转换类型转换二二类类型与系统预定义类类型与系统预定义2、类型转换函数、类型转换函数规则:规则:(1)可以将用户自定义的类类型转换成基本类型可以将用户自定义的类类型转换成基本类型(2) 无返回值,函数名就是转换类型无返回值,函数名就是转换类型(3) 无任何参数无任何参数定义格式:定义格式:class public: operator ( ); ;第5章运行时的多态性和抽象类#include iostream.hclass complex private: float real,imag; public: complex(float r

8、=0,float i=0) real=r;imag=i; coutConstructing.endl; operator float() /注意空格注意空格 coutTo float.endl; return real;第5章运行时的多态性和抽象类operator int() coutTo Int.endl; return int(real); void print() coutreal,imag)endl; void main() complex A(2.2,4.4); A.print(); coutfloat(A)*0.5endl; /coutA.operator float()*0.5e

9、ndl; complex B(4.4,6.6); B.print(); coutint(B)*2display(); /调用基类的调用基类的displayp = &g1;p-display(); /调用基类的调用基类的display第5章运行时的多态性和抽象类p 存在问题存在问题 指向基类的指针p,不管赋给它的对象地址的不同 语句“p-display()调用的始终是基类中定义的版本。p 根本原因根本原因 在派生类中虽然继承了基类的成员函数display() ,但在派生类中又定义了一个同名的display()函数,而这种改变在静态联编的条件下编译器并不知道。问题问题:那么,怎样获得我们那

10、么,怎样获得我们所希望的结果呢?所希望的结果呢?解决方案解决方案 必须通知编译器这种可能的改变,即需要进行动态动态联编联编。为了实现动态联编,C+提出了虚函数虚函数的概念第5章运行时的多态性和抽象类5.2.1 虚函数和运行时的多态性虚函数和运行时的多态性C+语言中,前边标有关键字语言中,前边标有关键字virtual的成员函数称为虚函的成员函数称为虚函数数(或虚拟函数或虚拟函数)。对于虚函数,系统将按照滞后联编的方式考。对于虚函数,系统将按照滞后联编的方式考虑对象的成员函数调用。虑对象的成员函数调用。声明虚函数的语句格式为:声明虚函数的语句格式为:virtual 返回值类型返回值类型 函数名函数

11、名(参数表参数表) 函数体函数体;第5章运行时的多态性和抽象类u声明虚函数时注意事项声明虚函数时注意事项 (1) 只有在只有在类层次类层次中才可以设计虚函数。只有一个类没有中才可以设计虚函数。只有一个类没有设计虚函数的必要。设计虚函数的必要。 (2) 若基类和派生类有同名同参的成员函数,基类被虚化,若基类和派生类有同名同参的成员函数,基类被虚化,派生类将自动被虚化派生类将自动被虚化 (3) 派生类中声明的虚函数派生类中声明的虚函数,其其成员函数名成员函数名、参数个数参数个数、参数类型以及返回类型,要和基类中参数类型以及返回类型,要和基类中声明的虚函数的函数名、声明的虚函数的函数名、参数个数、参

12、数类型以及返回类型参数个数、参数类型以及返回类型完全一样完全一样 (4) 若不满足若不满足(3),派生类虚特性消失派生类虚特性消失 (5) 基类未虚基类未虚,派生类虚化,派生类虚化,虚特性消失虚特性消失 (6) 由于使用虚函数时要由于使用虚函数时要利用赋值兼容规则利用赋值兼容规则,要求派生类,要求派生类必须由基类的必须由基类的公有继承公有继承方式产生。方式产生。第5章运行时的多态性和抽象类u不不能声明为虚函数能声明为虚函数的函数的函数 静态成员函数静态成员函数 根据静态函数的特性,它不属于某一个对象,不具备多态根据静态函数的特性,它不属于某一个对象,不具备多态性的条件和特征。性的条件和特征。内

13、联成员函数内联成员函数因为内联函数的执行代码是确定的,不具有多态性的特征。因为内联函数的执行代码是确定的,不具有多态性的特征。构造函数构造函数不能是虚函数,不能是虚函数,析构函数可以声明为虚函数!析构函数可以声明为虚函数!u虚析构函数的定义:虚析构函数的定义:virtual 类名类名(); 函数体函数体第5章运行时的多态性和抽象类通过通过 对象指针对象指针 对象引用对象引用调用虚函数实现动态联编调用虚函数实现动态联编 u虚函数的调用虚函数的调用p 应用虚函数,可以使程序员不必过多的考虑类的层次关系p 无须显示的写出虚函数的路径p 只需将对象指针指向相应的派生类或引用相应的对象,就可以实现动态联

14、编,实现对消息的正确响应。第5章运行时的多态性和抽象类Class Student private: char name20; public: virtual void display(); /利用虚函数实现滞后链编利用虚函数实现滞后链编;Class Graduate:public Student public:void display();第5章运行时的多态性和抽象类student s1(张三张三,电信电信0801);graduate g1(李四李四,电信电信0802);student *p;p = &s1;p-display(); /调用基类的调用基类的displayp = &

15、;g1;p-display();/调用派生类的调用派生类的display第5章运行时的多态性和抽象类利用虚函数实现运行时的多态性的设计方法是:利用虚函数实现运行时的多态性的设计方法是: (1) 设计一个类层次,并在类层次中定义一个或一个以上的虚函数。(2) 在外部程序中定义基类的对象指针。(3) 在外部程序中,当对象指针调用一个对象的虚函数时,若此时该对象指针指向基类对象,则系统就调用基类中的相应虚成员函数;若此时基类对象指针指向派生类对象,则系统就调用派生类中的相应成员函数。u这样就实现了运行时的多态性!这样就实现了运行时的多态性!第5章运行时的多态性和抽象类5.2.3 虚函数和派生类对基类

16、成员函数覆盖的区别虚函数和派生类对基类成员函数覆盖的区别1)虚函数也像派生类对基类成员函数的覆盖那样,在派虚函数也像派生类对基类成员函数的覆盖那样,在派生类中覆盖了基类的成员函数,而且要求派生类中定义虚函数生类中覆盖了基类的成员函数,而且要求派生类中定义虚函数的参数个数、参数类型和返回类型要与基类中定义虚函数的参的参数个数、参数类型和返回类型要与基类中定义虚函数的参数个数、参数类型和返回类型完全一样。数个数、参数类型和返回类型完全一样。 2)对于派生类对基类成员函数的覆盖来说,调用成员函数)对于派生类对基类成员函数的覆盖来说,调用成员函数的对象在程序编译时就已确定,即要么是基类对象,要么是派的

17、对象在程序编译时就已确定,即要么是基类对象,要么是派生类对象,只能属于固定的一种,不能在程序运行时改变。生类对象,只能属于固定的一种,不能在程序运行时改变。 第5章运行时的多态性和抽象类但对于虚函数来说,但对于虚函数来说,由于系统采用滞后联编的由于系统采用滞后联编的编译方式,编译方式,调用成员函数的对象要在程序运行时才调用成员函数的对象要在程序运行时才确定,要根据确定,要根据对象指针对象指针当前指向的对象是基类对象当前指向的对象是基类对象还是派生类对象,来决定当前调用的成员函数是基还是派生类对象,来决定当前调用的成员函数是基类的成员函数,还是派生类的成员函数。类的成员函数,还是派生类的成员函数

18、。 如果对象指针当前指向的是基类对象,则调用如果对象指针当前指向的是基类对象,则调用基类的成员函数;如果对象指针当前指向的是派生基类的成员函数;如果对象指针当前指向的是派生类对象,则调用派生类的成员函数。类对象,则调用派生类的成员函数。第5章运行时的多态性和抽象类编程实例编程实例1 大学人员问题。大学人员问题。设计要求:大学人员分为两类,一类是教学人员,设计要求:大学人员分为两类,一类是教学人员,另一类是行政人员,这两类人员的信息管理系统中,另一类是行政人员,这两类人员的信息管理系统中,一部分信息内容是相同的,但另一部分信息内容是不一部分信息内容是相同的,但另一部分信息内容是不相同的。设教学人

19、员的信息包括姓名、年龄和专业编相同的。设教学人员的信息包括姓名、年龄和专业编号,行政人员的信息包括姓名、年龄和业绩评级。号,行政人员的信息包括姓名、年龄和业绩评级。 现要求定义一个对象数组能保存现要求定义一个对象数组能保存3个学校教学人员个学校教学人员和和2个行政人员的实例对象,并打印出各自信息,并个行政人员的实例对象,并打印出各自信息,并设计一个测试程序进行测试。设计一个测试程序进行测试。第5章运行时的多态性和抽象类5.3 纯虚函数与抽象类纯虚函数与抽象类在一个图形系统中,有一个一般的闭合图形类CClosedFigureCClosedFigureCPolygonCCircleCRectang

20、leCTriangle问题:由于不知道问题:由于不知道CClosedFigure的数据如何表现,的数据如何表现,故它的故它的Perimeter、Area和和Draw函数无法实现?函数无法实现?第5章运行时的多态性和抽象类5.3.1 纯虚函数纯虚函数在基类中不对虚函数给出有意义的实现在基类中不对虚函数给出有意义的实现,它只是在派它只是在派生类中有具体的意义。这时基类中的虚函数只是一个生类中有具体的意义。这时基类中的虚函数只是一个入口,具体的目的地由不同的派生类中的对象决定。入口,具体的目的地由不同的派生类中的对象决定。这个虚函数称为这个虚函数称为纯虚函数纯虚函数。class virtual ()

21、=0;.;第5章运行时的多态性和抽象类5.3.2 抽象类抽象类p定义定义 至少包含一个纯虚函数的类,称为抽象类。至少包含一个纯虚函数的类,称为抽象类。p 作用作用抽象类作为派生类组抽象类作为派生类组统一的根统一的根,组成一个类层次组成一个类层次。纯虚函。纯虚函数为该类层次提化供数为该类层次提化供统一接口统一接口。派生类可以具体化这些虚派生类可以具体化这些虚函数的操作行为,完成各个类特有的属性函数的操作行为,完成各个类特有的属性p 抽象类不能初始化具体对象,但可以定义指针变量抽象类不能初始化具体对象,但可以定义指针变量必须在派生类中必须在派生类中重载纯虚函数重载纯虚函数,否则会产生程序的运行错,

22、否则会产生程序的运行错误!误!第5章运行时的多态性和抽象类class Aprotected:int x;public:A()x =1000; virtual void print()=0; /定义纯虚函数定义纯虚函数;class B:public A /派生类派生类private: int y;public:B() y=2000;void print()cout “y=”yn;/重新定义纯虚函数重新定义纯虚函数;class C:public A /派生类派生类int z;public:C()z=3000;void print()cout “z=”zprint();pa=&c; pa-print(); A a; pa=&a; pa-print( );y=2000z=3000抽象类抽象类不能定义抽象类的对象不能定义抽象类的对象第5章运

温馨提示

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

评论

0/150

提交评论