版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、面向对象程序设计第5章 多态与抽象类10/16/20221第5章多态与抽象类面向对象程序设计第5章 多态与抽象类10/11/202 内容提要5.1 类层次的多态问题5.2 类型兼容规则(重点)5.3 多态的概念5.4 多态的分类5.5 联编5.6 虚函数(重点)5.7 抽象类与纯虚函数(重点)10/16/20222第5章多态与抽象类 内容提要5.1 类层次的多态问题10/11/20222提出问题【例5-1】在例4-1程序中存在的两个不足:(1)基类Pay()和Display()的函数体均为空,在实现部分仍要写出函数体,显得冗余。(2)在主函数中,建立了4个不同类的对象,进行了类似的操作,重复写
2、了4遍类似的语句,程序不够简洁。10/16/20223第5章多态与抽象类提出问题【例5-1】在例4-1程序中存在的两个不足:10/1分析问题基类设置成员函数Pay()和Display()的目的是为了统一规定类簇的基本行为,虽有冗余,但也必要。为此,C+提供了纯虚函数来解决此问题。 10/16/20224第5章多态与抽象类分析问题基类设置成员函数Pay()和Display()的目的在主函数中建立了4个不同类的对象,进行了类似的操作,重复写了4遍类似的语句。应该怎样有效地来处理它们同样的行为呢?我们首先想到的是用循环解决,但调用这些同名函数的对象却不相同。分析这些对象有一个共同点,那就是来自于同一
3、个基类,而基类与派生类对象有什么关系呢?事实上,它们遵循类型兼容规则。10/16/20225第5章多态与抽象类在主函数中建立了4个不同类的对象,进行了类似的操作,重复写了Employee *emp4=&m1,&t1,&s1,&sm1; /声明抽象类指针数组for(int i=0;iPay(); /单一指令,实现多态,计算指针指向对象的工资empi-Display();/单一指令,实现多态,输出指针指向对象的信息10/16/20226第5章多态与抽象类Employee *emp4=&m1,&t1,&s1,5.2类型兼容规则类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代
4、。10/16/20227第5章多态与抽象类5.2类型兼容规则类型兼容规则是指在需要基类对象的任何地方,通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。 10/16/20228第5章多态与抽象类通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所类型兼容规则中所指替代包括以下情况:(1)派生类的对象可以赋值给基类的对象。(2)派生类的对象可以初始化基类的引用。(3)派生类的对象的地址可以赋值给基类的指针变量。在替代之后,派生类对象就可以作为基类的对象使用,但只能访问从基类继承的成员
5、。10/16/20229第5章多态与抽象类类型兼容规则中所指替代包括以下情况:10/11/20229第【例5-3】示例类型兼容规则的应用。教材P261,该程序的运行结果为:Base classBase classBase classDerivel classDerive2 class 10/16/202210第5章多态与抽象类【例5-3】示例类型兼容规则的应用。10/11/202210根据类型兼容规则,基类指针p可以指向派生类对象obj2、obj3(即派生类对象可以代替基类对象,给基类指针赋值),但编译时,编译器根据p的类型是基类型,自动调用基类的who(),所以结果如上所示。 10/16/2
6、02211第5章多态与抽象类根据类型兼容规则,基类指针p可以指向派生类对象obj2、ob【思考题5-3】如果基类指针要访问派生类的who(),怎么办? C+提供了多态机制来解决这个问题。类型兼容规则是C+多态的重要基础。 10/16/202212第5章多态与抽象类【思考题5-3】如果基类指针要访问派生类的who(),怎么办多态多态(Polymorphism)是指具有相似功能的不同函数使用同一个名称来实现,从而可以使用相同的调用方式来调用这些具有不同功能的同名函数的特性。 10/16/202213第5章多态与抽象类多态多态(Polymorphism)是指具有相似功能的不同函5.4 多态的分类C+
7、支持的多态可以分为四种类型:重载多态:函数重载和运算符重载强制多态:强制类型转换包含多态:虚函数参数多态:函数模板和类模板 10/16/202214第5章多态与抽象类5.4 多态的分类C+支持的多态可以分为四种类型:10/联编联编是指把一个标识符名和一个存储地址联系在一起的过程。即函数调用与某个函数在多态的实现过程中,确定调用哪个同名联系的过程,又称绑定。分为:静态联编动态联编10/16/202215第5章多态与抽象类联编联编是指把一个标识符名和一个存储地址联系在一起的过程。即静态联编是在编译阶段完成的联编。例5-2、例5-3及以前的函数重载都是采用静态联编方式。例5-4,教材P265,是静态
8、联编。动态联编是在运行阶段完成的联编。 10/16/202216第5章多态与抽象类静态联编是在编译阶段完成的联编。例5-2、例5-3及以前的函在例5-4中,静态联编把基类指针ps指向的对象绑定到基类上,而在运行时进行动态联编将把ps指向的对象绑定到派生类上。10/16/202217第5章多态与抽象类在例5-4中,静态联编把基类指针ps指向的对象绑定到基类上,可见,同一个指针,在不同阶段被绑定的类对象将是不同的,进而被关联的类成员函数也是不同的。如何来确定是用静态联编还是用动态联编呢?C+规定,动态联编通过继承和虚函数来实现。10/16/202218第5章多态与抽象类可见,同一个指针,在不同阶段
9、被绑定的类对象将是不同的,进而被虚函数是动态联编的基础。下面介绍虚函数。10/16/202219第5章多态与抽象类虚函数是动态联编的基础。下面介绍虚函数。10/11/20225.6 虚函数虚函数就是在基类中被关键字virtual说明、并在一个或多个派生类中被重新定义的成员函数。10/16/202220第5章多态与抽象类5.6 虚函数虚函数就是在基类中被关键字virtual说明、声明虚函数的格式如下:virtual ();10/16/202221第5章多态与抽象类声明虚函数的格式如下:10/11/202221第5章多态与抽在派生类中重新定义虚函数时,其函数原型包括返回类型、函数名、参数个数与参数
10、类型的顺序,都必须与基类中的原型必须相同。10/16/202222第5章多态与抽象类在派生类中重新定义虚函数时,其函数原型包括返回类型、函数名、一个函数一旦被声明为虚函数,则无论声明它的类被继承了多少层,在每一层派生类中该函数都保持虚函数特性。因此,在派生类中重新定义该函数时,可以省略关键字virtual。但是,为了提高程序的可读性,往往不省略。10/16/202223第5章多态与抽象类一个函数一旦被声明为虚函数,则无论声明它的类被继承了多少层,在程序运行时,不同类的对象调用各自的虚函数,这就是运行时多态。10/16/202224第5章多态与抽象类在程序运行时,不同类的对象调用各自的虚函数,这
11、就是运行时多态【例5-5】将例5-4基类的成员函数print()设为虚函数,采用对象指针调用虚函数,进而实现动态联编。 10/16/202225第5章多态与抽象类【例5-5】将例5-4基类的成员函数print()设为虚函数该程序的运行结果为:A studentA graduate studentA studentA studentA graduate student10/16/202226第5章多态与抽象类该程序的运行结果为:10/11/202226第5章多态与抽象【思考题5-5】如果将例5-5中Student类改为:class Studentpublic: virtual void prin
12、t(); /虚函数的声明;virtual void Student:print() /虚函数的实现 coutA studentendl;10/16/202227第5章多态与抽象类【思考题5-5】如果将例5-5中Student类改为:10/注意:当有虚函数声明时,virtual关键字只用在虚函数的声明中,不能用在虚函数定义中。 10/16/202228第5章多态与抽象类注意:当有虚函数声明时,virtual关键字只用在虚函数的声【思考题5-4】将例5-5中用对象调用虚函数,其结果如何?【注意】只有通过对象指针或对象引用来调用虚函数,才能实现动态联编。如果采用对象来调用虚函数,则采用的是静态联编方
13、式。10/16/202229第5章多态与抽象类【思考题5-4】将例5-5中用对象调用虚函数,其结果如何?1【例5-6】将例5-4基类的成员函数print()设为虚函数,采用对象引用调用虚函数,进而实现动态联编。 10/16/202230第5章多态与抽象类【例5-6】将例5-4基类的成员函数print()设为虚函数运行结果表明,只要定义一个基类的对象指针或对象引用,就可以调用期望的虚函数。思考题:如果将对象引用或对象指针换为对象,那么是静态联编。10/16/202231第5章多态与抽象类运行结果表明,只要定义一个基类的对象指针或对象引用,就可以调在实际应用中,编程人员不必过多地考虑类的层次关系,
14、无须显式地写出虚函数的路径,只须将对象指针指向相应的派生类或引用相应的对象,通过动态联编就可以对消息做出正确的反应。10/16/202232第5章多态与抽象类在实际应用中,编程人员不必过多地考虑类的层次关系,无须显式地小结(1)如果你期望在派生类中重新定义一个成员函数,那么你就应该在基类中把该函数设为virtual。(2)以单一指令调用不同函数,这种性质就是多态。(3)虚函数是C+语言的多态性质和动态绑定的关键。(4)虚函数派生下去仍是虚函数,而且可以省略virtual关键词。10/16/202233第5章多态与抽象类小结(1)如果你期望在派生类中重新定义一个成员函数,那么你就【思考题5-8】
15、虚函数与虚拟继承有什么相似的地方?他们之间有没有联系?如果能了解C+编译器对于虚函数的实现形式,我们就能知道为什么虚函数可以实现动态绑定。下面介绍虚函数表。10/16/202234第5章多态与抽象类【思考题5-8】虚函数与虚拟继承有什么相似的地方?他们之间有5.6.3 虚函数表为了达到动态绑定的目的,C+编译器通过某个表格,在执行期间“间接”调用实际上欲绑定的函数,这样的表格称为虚函数表(vtable)。10/16/202235第5章多态与抽象类5.6.3 虚函数表为了达到动态绑定的目的,C+编译器通每一个含有虚函数的类,编译器都为它做一个虚函数表,表中的每一项都指向一个虚函数的地址,实现上是
16、一个函数指针的数组。此外,编译器也会为类加上一个数据成员,是一个指向该虚函数表的指针(vptr)。 10/16/202236第5章多态与抽象类每一个含有虚函数的类,编译器都为它做一个虚函数表,表中的每一Wind objectvptrStringed objectvptrPercussion objectvptr&Wind:play()& Percussion:play()& Stringed:play()10/16/202237第5章多态与抽象类Wind objectvptrStringed object当通过对象调用虚函数时,是通过vptr找到虚函数表,再找出虚函数的真正地址。至于基类指针或
17、引用指向派生类对象时,调用的是派生类虚函数,其奥妙在于虚函数表以及一种间接调用方式:10/16/202238第5章多态与抽象类当通过对象调用虚函数时,是通过vptr找到虚函数表,再找出虚虚函数表中的内容依据类中的虚函数声明次序,一一填入函数指针。派生类会继承基类的虚函数表(以及其它所有可以继承的成员),我们在派生类中改写虚函数时,虚函数表也受到了影响,表中每一项所指向函数地址将不再是基类中的函数地址,而是派生类的函数地址。10/16/202239第5章多态与抽象类虚函数表中的内容依据类中的虚函数声明次序,一一填入函数指针。因此,一个指向Student对象的指针,所调用的print函数就是Stu
18、dent:print(), 而一个指向GStudent对象的指针,所调用的print函数就是GStudent:print()。 10/16/202240第5章多态与抽象类因此,一个指向Student对象的指针,所调用的print函将一个类的成员函数定义为虚函数有利于编程,尽管它会引起一些额外的开销。那么,是否所有成员函数都可以声明为虚函数呢?10/16/202241第5章多态与抽象类将一个类的成员函数定义为虚函数有利于编程,尽管它会引起一些额一般来说,可将类簇中具有共性的成员函数声明为虚函数,而具有个性的函数没有必要声明为虚函数。但是下面的情况例外:10/16/202242第5章多态与抽象类一
19、般来说,可将类簇中具有共性的成员函数声明为虚函数,而具有个(1)静态成员函数不能声明为虚函数。因为静态成员函数不属于某一个对象,没有多态性的特征。(2)构造函数不能是虚函数。构造函数是在定义对象时被调用,完成对象的初始化,此时对象还没有完全建立。虚函数作为运行时的多态性的基础,主要是针对对象的,而构造函数是在对象产生之前运行的。所以,将构造函数声明为虚函数是没有意义的。 10/16/202243第5章多态与抽象类(1)静态成员函数不能声明为虚函数。因为静态成员函数不属于某(3)内联成员函数不能声明为虚函数。因为内联函数的执行代码是明确的,在编译时已被替换,没有多态性的特征。如果将那些在类声明时
20、就定义内容的成员函数声明为虚函数,此时函数不是内联函数,而以多态性出现。10/16/202244第5章多态与抽象类(3)内联成员函数不能声明为虚函数。因为内联函数的执行代码是(4)析构函数可以是虚函数,且往往被定义为虚函数。一般来说,若某类中有虚函数,则其析构函数也应当定义为虚函数。10/16/202245第5章多态与抽象类(4)析构函数可以是虚函数,且往往被定义为虚函数。一般来说,特别是需要析构函数完成一些有意义的操作,如释放内存时,由于实施多态性时是通过将基类的指针指向派生类的对象来完成的,如果删除该指针,就会调用该指针指向的派生类的析构函数,而派生类的析构函数又自动调用基类的析构函数,这
21、样整个派生类的对象才被完全释放。10/16/202246第5章多态与抽象类特别是需要析构函数完成一些有意义的操作,如释放内存时,由于实因此,析构函数常被声明为虚函数。如果一个类的析构函数是虚函数,那么,由它派生的所有子类的析构函数也是虚函数。下面介绍虚析构函数。10/16/202247第5章多态与抽象类因此,析构函数常被声明为虚函数。如果一个类的析构函数是虚函数5.6.4 虚析构函数虚析构函数的声明格式如下:virtual ();【例5-7】虚析构函数示例。教材P27210/16/202248第5章多态与抽象类5.6.4 虚析构函数虚析构函数的声明格式如下:10/11/利用虚函数可以使所设计的
22、软件系统变得灵活,提高了代码的可重用性。虚函数为一个类簇中所有派生类的同一行为提供了统一的接口,使得程序员在使用一个类簇时只须记住一个接口即可。10/16/202249第5章多态与抽象类利用虚函数可以使所设计的软件系统变得灵活,提高了代码的可重用注意事项(1)如果在派生类中没有重新定义虚函数,则派生类的对象将使用基类的虚函数代码。(2)在派生类中重新定义虚函数时,必须保证函数值类型和参数与基类中的声明完全一致。否则,派生类的函数也不具备多态性。10/16/202250第5章多态与抽象类注意事项(1)如果在派生类中没有重新定义虚函数,则派生类的对根据上述介绍,我们可以将例5-1的Pay()和Di
23、splay()定义为虚函数,从而解决例4-1遗留下来的第二个问题。10/16/202251第5章多态与抽象类根据上述介绍,我们可以将例5-1的Pay()和Display另外,公司的人员有4类,它们的基类Employee实际上是不需要实例化对象的,Employee也无法为虚函数定义具体的实现,这时可以将Employee声明为纯虚函数。包含纯虚函数的类称为抽象类。10/16/202252第5章多态与抽象类另外,公司的人员有4类,它们的基类Employee实际上是不5.7 抽象类和纯虚函数抽象类专门作为基类派生新类。抽象类的主要作用是将有关的派生类组织在一个继承层次结构中,由抽象类为它们提供一个公共
24、的根,相关的派生类就从这个根派生出来。 含有纯虚函数的类就是抽象类。 10/16/202253第5章多态与抽象类5.7 抽象类和纯虚函数抽象类专门作为基类派生新类。抽象类在例4-1中遗留的另一个问题是: employee类的成员函数pay()和display()的函数体为空,在实现部分仍要写出函数体,显得冗余。事实上,employee类的成员函数根本不会被调用,所以不必定义它。于是+提供了纯虚函数来解决这个问题。 10/16/202254第5章多态与抽象类在例4-1中遗留的另一个问题是: employee类的成员函纯虚函数纯虚函数是为了解决在基类中无法实现的函数,而在派生类中再给出函数的具体实
25、现,它只需要在基类中说明函数原型用来规定整个类簇的统一接口形式。10/16/202255第5章多态与抽象类纯虚函数纯虚函数是为了解决在基类中无法实现的函数,而在派生类纯虚函数的声明格式为:virtual ()=0;10/16/202256第5章多态与抽象类纯虚函数的声明格式为:10/11/202256第5章多态与抽纯虚函数与函数体为空的虚函数是有区别的:前者有函数体,而后者没有函数体;前者所在的类是抽象类,不能直接进行实例化,而后者所在的类是可以实例化的。 10/16/202257第5章多态与抽象类纯虚函数与函数体为空的虚函数是有区别的:10/11/2022【例5-9】示例纯虚函数及抽象类。计算图形面积。例如,要定义一个Square类和Circle类,它们有共同的属性x、y,以及共同的操作setvalue()和area(),由于area()在两个类的计算方法不同,但又属于一个类簇,为此,定义一个抽象类Shape,统一它们的属
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 方管购销交付协议3篇
- 摩托车交易合同格式3篇
- 安全驾驶责任准则3篇
- 工业用井施工协议范本3篇
- 旅游包车预订合同3篇
- 招标管理指南3篇
- 智能办公大清包施工合同
- 隧道安全防护工程合同
- 仓储物流材料员聘用合同
- 互联网环保公司网络布线服务合同
- 少一点麻痹思想多一份生产安全
- 2025年日历表带农历【阴历】完美打印版
- 《海上钢琴师》课件
- 广东省深圳市2022年中考英语一模试题含解析
- 2024年高中语文选择性必修上、中教考衔接作文汇编
- 部编版语文六年级上册词句段运用练习
- 会计专科职业生涯规划与管理
- 2023年电大行政组织学试卷期末考试试题及答案
- 2024年1月上海春季高考模拟英语试卷完整版二(含答案+听力MP3)
- 大学本科机械专业仿生类蜻蜓飞行器研究毕业论文
- 《金庸武侠经典》课件
评论
0/150
提交评论