面向对象程序设计ppt课件

上传人:tian****1990 文档编号:83109054 上传时间:2019-02-26 格式:PPT 页数:62 大小:277.31KB
返回 下载 相关 举报
面向对象程序设计ppt课件_第1页
第1页 / 共62页
面向对象程序设计ppt课件_第2页
第2页 / 共62页
面向对象程序设计ppt课件_第3页
第3页 / 共62页
面向对象程序设计ppt课件_第4页
第4页 / 共62页
面向对象程序设计ppt课件_第5页
第5页 / 共62页
点击查看更多>>
资源描述

《面向对象程序设计ppt课件》由会员分享,可在线阅读,更多相关《面向对象程序设计ppt课件(62页珍藏版)》请在金锄头文库上搜索。

1、面向对象程序设计,第5章 多态与抽象类,内容提要,5.1 类层次的多态问题 5.2 类型兼容规则(重点) 5.3 多态的概念 5.4 多态的分类 5.5 联编 5.6 虚函数(重点) 5.7 抽象类与纯虚函数(重点),第5章多态与抽象类,2019/2/26,3,提出问题,【例5-1】在例4-1程序中存在的两个不足: (1)基类Pay()和Display()的函数体均为空,在实现部分仍要写出函数体,显得冗余。 (2)在主函数中,建立了4个不同类的对象,进行了类似的操作,重复写了4遍类似的语句,程序不够简洁。,第5章多态与抽象类,2019/2/26,4,分析问题,基类设置成员函数Pay()和Dis

2、play()的目的是为了统一规定类簇的基本行为,虽有冗余,但也必要。为此,C+提供了纯虚函数来解决此问题。,第5章多态与抽象类,2019/2/26,5,在主函数中建立了4个不同类的对象,进行了类似的操作,重复写了4遍类似的语句。 应该怎样有效地来处理它们同样的行为呢?我们首先想到的是用循环解决,但调用这些同名函数的对象却不相同。 分析这些对象有一个共同点,那就是来自于同一个基类,而基类与派生类对象有什么关系呢?事实上,它们遵循类型兼容规则。,第5章多态与抽象类,2019/2/26,6,Employee *emp4=/单一指令,实现多态,输出指针指向对象的信息 ,第5章多态与抽象类,2019/2

3、/26,7,5.2类型兼容规则,类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。,第5章多态与抽象类,2019/2/26,8,通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。,第5章多态与抽象类,2019/2/26,9,类型兼容规则中所指替代包括以下情况: (1)派生类的对象可以赋值给基类的对象。 (2)派生类的对象可以初始化基类的引用。 (3)派生类的对象的地址可以赋值给基类的指针变量。 在替代之后,派生类对象就可以作为基类的对象使用,但只能访问从基类继承的

4、成员。,第5章多态与抽象类,2019/2/26,10,【例5-3】示例类型兼容规则的应用。 教材P261,该程序的运行结果为: Base class Base class Base class Derivel class Derive2 class,第5章多态与抽象类,2019/2/26,11,根据类型兼容规则,基类指针p可以指向派生类对象obj2、obj3(即派生类对象可以代替基类对象,给基类指针赋值),但编译时,编译器根据p的类型是基类型,自动调用基类的who(),所以结果如上所示。,第5章多态与抽象类,2019/2/26,12,【思考题5-3】如果基类指针要访问派生类的who(),怎么办

5、? C+提供了多态机制来解决这个问题。 类型兼容规则是C+多态的重要基础。,第5章多态与抽象类,2019/2/26,13,多态,多态(Polymorphism)是指具有相似功能的不同函数使用同一个名称来实现,从而可以使用相同的调用方式来调用这些具有不同功能的同名函数的特性。,第5章多态与抽象类,2019/2/26,14,5.4 多态的分类,C+支持的多态可以分为四种类型: 重载多态:函数重载和运算符重载 强制多态:强制类型转换 包含多态:虚函数 参数多态:函数模板和类模板,第5章多态与抽象类,2019/2/26,15,联编,联编是指把一个标识符名和一个存储地址联系在一起的过程。即函数调用与某个

6、函数在多态的实现过程中,确定调用哪个同名联系的过程,又称绑定。分为: 静态联编 动态联编,第5章多态与抽象类,2019/2/26,16,静态联编是在编译阶段完成的联编。例5-2、例5-3及以前的函数重载都是采用静态联编方式。 例5-4,教材P265,是静态联编。 动态联编是在运行阶段完成的联编。,第5章多态与抽象类,2019/2/26,17,在例5-4中,静态联编把基类指针ps指向的对象绑定到基类上,而在运行时进行动态联编将把ps指向的对象绑定到派生类上。,第5章多态与抽象类,2019/2/26,18,可见,同一个指针,在不同阶段被绑定的类对象将是不同的,进而被关联的类成员函数也是不同的。 如

7、何来确定是用静态联编还是用动态联编呢? C+规定,动态联编通过继承和虚函数来实现。,第5章多态与抽象类,2019/2/26,19,虚函数是动态联编的基础。下面介绍虚函数。,第5章多态与抽象类,2019/2/26,20,5.6 虚函数,虚函数就是在基类中被关键字virtual说明、并在一个或多个派生类中被重新定义的成员函数。,第5章多态与抽象类,2019/2/26,21,声明虚函数的格式如下: virtual ();,第5章多态与抽象类,2019/2/26,22,在派生类中重新定义虚函数时,其函数原型包括返回类型、函数名、参数个数与参数类型的顺序,都必须与基类中的原型必须相同。,第5章多态与抽象

8、类,2019/2/26,23,一个函数一旦被声明为虚函数,则无论声明它的类被继承了多少层,在每一层派生类中该函数都保持虚函数特性。因此,在派生类中重新定义该函数时,可以省略关键字virtual。但是,为了提高程序的可读性,往往不省略。,第5章多态与抽象类,2019/2/26,24,在程序运行时,不同类的对象调用各自的虚函数,这就是运行时多态。,第5章多态与抽象类,2019/2/26,25,【例5-5】将例5-4基类的成员函数print()设为虚函数,采用对象指针调用虚函数,进而实现动态联编。,第5章多态与抽象类,2019/2/26,26,该程序的运行结果为: A student A gradu

9、ate student A student A student A graduate student,第5章多态与抽象类,2019/2/26,27,【思考题5-5】如果将例5-5中Student类改为: class Student public: virtual void print(); /虚函数的声明 ; virtual void Student:print() /虚函数的实现 cout“A student“endl; ,第5章多态与抽象类,2019/2/26,28,注意:当有虚函数声明时,virtual关键字只用在虚函数的声明中,不能用在虚函数定义中。,第5章多态与抽象类,2019/2/

10、26,29,【思考题5-4】将例5-5中用对象调用虚函数,其结果如何? 【注意】只有通过对象指针或对象引用来调用虚函数,才能实现动态联编。如果采用对象来调用虚函数,则采用的是静态联编方式。,第5章多态与抽象类,2019/2/26,30,【例5-6】将例5-4基类的成员函数print()设为虚函数,采用对象引用调用虚函数,进而实现动态联编。,第5章多态与抽象类,2019/2/26,31,运行结果表明,只要定义一个基类的对象指针或对象引用,就可以调用期望的虚函数。 思考题:如果将对象引用或对象指针换为对象,那么是静态联编。,第5章多态与抽象类,2019/2/26,32,在实际应用中,编程人员不必过

11、多地考虑类的层次关系,无须显式地写出虚函数的路径,只须将对象指针指向相应的派生类或引用相应的对象,通过动态联编就可以对消息做出正确的反应。,第5章多态与抽象类,2019/2/26,33,小结,(1)如果你期望在派生类中重新定义一个成员函数,那么你就应该在基类中把该函数设为virtual。 (2)以单一指令调用不同函数,这种性质就是“多态“。 (3)虚函数是C+语言的多态性质和动态绑定的关键。 (4)虚函数派生下去仍是虚函数,而且可以省略virtual关键词。,第5章多态与抽象类,2019/2/26,34,【思考题5-8】虚函数与虚拟继承有什么相似的地方?他们之间有没有联系? 如果能了解C+编译

12、器对于虚函数的实现形式,我们就能知道为什么虚函数可以实现动态绑定。下面介绍虚函数表。,第5章多态与抽象类,2019/2/26,35,5.6.3 虚函数表,为了达到动态绑定的目的,C+编译器通过某个表格,在执行期间“间接”调用实际上欲绑定的函数,这样的表格称为虚函数表(vtable)。,第5章多态与抽象类,2019/2/26,36,每一个含有虚函数的类,编译器都为它做一个虚函数表,表中的每一项都指向一个虚函数的地址,实现上是一个函数指针的数组。此外,编译器也会为类加上一个数据成员,是一个指向该虚函数表的指针(vptr)。,第5章多态与抽象类,2019/2/26,37,第5章多态与抽象类,2019

13、/2/26,38,当通过对象调用虚函数时,是通过vptr找到虚函数表,再找出虚函数的真正地址。 至于基类指针或引用指向派生类对象时,调用的是派生类虚函数,其奥妙在于虚函数表以及一种间接调用方式:,第5章多态与抽象类,2019/2/26,39,虚函数表中的内容依据类中的虚函数声明次序,一一填入函数指针。 派生类会继承基类的虚函数表(以及其它所有可以继承的成员),我们在派生类中改写虚函数时,虚函数表也受到了影响,表中每一项所指向函数地址将不再是基类中的函数地址,而是派生类的函数地址。,第5章多态与抽象类,2019/2/26,40,因此,一个指向Student对象的指针,所调用的print函数就是S

14、tudent:print(), 而一个指向GStudent对象的指针,所调用的print函数就是GStudent:print()。,第5章多态与抽象类,2019/2/26,41,将一个类的成员函数定义为虚函数有利于编程,尽管它会引起一些额外的开销。 那么,是否所有成员函数都可以声明为虚函数呢?,第5章多态与抽象类,2019/2/26,42,一般来说,可将类簇中具有共性的成员函数声明为虚函数,而具有个性的函数没有必要声明为虚函数。但是下面的情况例外:,第5章多态与抽象类,2019/2/26,43,(1)静态成员函数不能声明为虚函数。因为静态成员函数不属于某一个对象,没有多态性的特征。 (2)构造

15、函数不能是虚函数。构造函数是在定义对象时被调用,完成对象的初始化,此时对象还没有完全建立。虚函数作为运行时的多态性的基础,主要是针对对象的,而构造函数是在对象产生之前运行的。所以,将构造函数声明为虚函数是没有意义的。,第5章多态与抽象类,2019/2/26,44,(3)内联成员函数不能声明为虚函数。因为内联函数的执行代码是明确的,在编译时已被替换,没有多态性的特征。如果将那些在类声明时就定义内容的成员函数声明为虚函数,此时函数不是内联函数,而以多态性出现。,第5章多态与抽象类,2019/2/26,45,(4)析构函数可以是虚函数,且往往被定义为虚函数。一般来说,若某类中有虚函数,则其析构函数也

16、应当定义为虚函数。,第5章多态与抽象类,2019/2/26,46,特别是需要析构函数完成一些有意义的操作,如释放内存时,由于实施多态性时是通过将基类的指针指向派生类的对象来完成的,如果删除该指针,就会调用该指针指向的派生类的析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象才被完全释放。,第5章多态与抽象类,2019/2/26,47,因此,析构函数常被声明为虚函数。如果一个类的析构函数是虚函数,那么,由它派生的所有子类的析构函数也是虚函数。 下面介绍虚析构函数。,第5章多态与抽象类,2019/2/26,48,5.6.4 虚析构函数,虚析构函数的声明格式如下: virtual (); 【例5-7】虚析构函数示例。教材P272,第5章多态与抽象类,2019/2/26,49,利用虚函数可以使所设计的软件系统变得灵活,提高了代码的可重用性。 虚函数为一个类簇中所有派生类的同一行为提供了统一的接口,使得程序员在使用一个类簇时只须记住一个接口即可。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号