多态性与虚函数课件

上传人:F****n 文档编号:88149510 上传时间:2019-04-20 格式:PPT 页数:36 大小:169.50KB
返回 下载 相关 举报
多态性与虚函数课件_第1页
第1页 / 共36页
多态性与虚函数课件_第2页
第2页 / 共36页
多态性与虚函数课件_第3页
第3页 / 共36页
多态性与虚函数课件_第4页
第4页 / 共36页
多态性与虚函数课件_第5页
第5页 / 共36页
点击查看更多>>
资源描述

《多态性与虚函数课件》由会员分享,可在线阅读,更多相关《多态性与虚函数课件(36页珍藏版)》请在金锄头文库上搜索。

1、C+程序设计,第8章(2) 多态性与虚函数,主要内容,C+的多态性 动态多态性的实现条件 虚函数的声明 虚函数的特性与调用 静态关联、动态关联 虚析构函数 纯虚函数 抽象类 综合实例,C+的多态性,多态性:指对不同类型的对象发送同样的消息(即调用同名的函数),不同类型的对象在接收时会产生不同的行为(即执行各自同名的函数)。 编译时多态性(静态多态性):指在编译阶段,系统就可根据所操作的对象,确定其具体的操作。编译时多态性是通过函数重载、运算符重载来实现的。函数重载是根据函数调用式中所给出的实参的类型或实参的个数,在编译阶段系统就可确定调用的是同名函数中的哪一个。运算符重载是根据运算式中所给出的

2、运算对象的类型,在编译阶段系统就可确定执行的是同种运算中的哪一个。 运行时多态性(动态多态性):指在编译阶段,系统仅根据函数调用式是无法确定调用的是同名函数中的哪一个;必须在程序运行过程中,动态确定所要调用函数的当前对象,并根据当前对象的类型来确定调用的是同名函数中的哪一个。 运行时多态性是通过 “类的继承关系” 加上 “虚函数” 联合起来实现的。,动态多态性的实现条件,要有类的继承层次结构:一个基类可以派生出不同的派生类,各派生类中可以新增与基类中的函数名字相同、参数个数及类型也相同的成员,这些同名的成员函数在不同的派生类中就有不同的含义!这样,在类的继承结构中,不同的层次上出现了名字相同、

3、参数个数及类型也相同、但功能不同的函数! 引入虚函数:作用是在由一个基类派生出的类体系中实现 “一个接口,多种方法”,主要用于建立通用程序。对于同一类体系中的各层次派生类,使用虚函数可实现统一的类接口,以便用相同的方式对各层次派生类的对象进行操作。虚函数是基类的成员函数,是为了实现某一种功能而假设的虚拟函数,在该基类的各层次派生类中对该虚函数可有各自不同的定义 ! 要能体现虚函数的特性:必须通过基类的对象指针、基类的对象引用来调用各层次派生类对象的同名虚函数,才能体现虚函数的特性!因为只有这样才能用相同的调用方式去调用不同层次派生类对象的同名虚函数,从而实现动态多态性。,虚函数的声明,虚函数的

4、声明:class 基类 virtual 返回值类型 成员函数名 ( 形参表 ) 函数体 ; 当一个基类的某成员函数声明为虚函数,则在该基类的所有派生类中,与虚函数同名、参数个数及类型相同、且返回值类型也相同的,不论是否有关键字 virtual 修饰,都是虚函数,反之不然。但要注意:若在派生类中只是与虚函数同名,而参数个数或类型有不同时,属于函数重载,不是虚函数! virtual 只是用在类中声明虚函数,若在类外定义虚函数前面不要加 virtual。 构造函数、静态成员函数不能声明为虚函数!析构函数可以声明为虚函数。,虚函数的特性与调用,如何体现虚函数的特性?只有通过基类的对象指针、基类的对象引

5、用来调用派生类对象的虚函数时,才能体现虚函数的特性!而通过派生类对象的对象名、对象指针、对象引用来调用虚函数时,无法体现虚函数的特性! 派生类对象中一般成员函数的调用方法: 可通过派生类对象的对象名、对象指针、对象引用来调用!调用过程:若派生类新增成员函数中存在该函数,则被调用;若不存在,则调用上一层基类中的该函数;若这一层基类中也不存在,就继续往上一层寻找 ,直至找到该函数并被调用。 派生类对象中一般成员函数的调用方法: 可通过基类的对象指针、基类的对象引用来调用派生类对象中的一般成员函数!但只能调用派生类中从该基类继承过来的那部分成员函数!,虚函数的特性与调用,派生类对象中虚函数的调用方法

6、: 派生类对象的虚函数也是成员函数,可按一般成员函数的方式调用!即:可通过派生类对象的对象名、对象指针、对象引用来调用!调用过程与一般成员函数的调用过程相同!由此可见,这种调用方式无法体现虚函数的特性! 派生类对象中虚函数的调用方法: 可通过基类的对象指针、基类的对象引用来调用派生类对象的虚函数!调用过程:调用的是派生类中的虚函数!若派生类中没有重新定义该虚函数,则调用的是上一层基类中的该虚函数;若在这一层基类中也没有重新定义该虚函数,就继续往上一层寻找 ,直至基类的对象指针、基类的对象引用它们本身所属的那一层基类! 动态多态性的实现:可以让基类的对象指针(或基类的对象引用)先后指向(或先后引

7、用)同一类族中不同派生类的对象,以便用相同的调用方式去调用不同派生类对象中的同名虚函数,从而实现动态多态性。,【例】(派生类对象中一般成员函数的调用方法:可通过派生类对象的对象名、对象指针、对象引用来调用!注意调用过程。) # include class A int x ; public: A ( int a ) x = a ; void g( ) cout f( ) ; pd-g( ) ; D ,【例】(派生类对象中虚函数的调用方法:可通过派生类对象的对象名、对象指针、对象引用来调用!注意调用过程与一般成员函数相同!由此可见,这种调用方式无法体现虚函数的特性!) # include clas

8、s A int x ; public: A ( int a ) x = a ; virtual void g( ) cout f( ) ; pd-g( ) ; D ,【例】(派生类对象中一般成员函数的调用方法:可通过基类的对象指针、基类的对象引用来调用!但只能调用派生类中从该基类继承来的那部分成员函数!) # include class A int x ; public: A ( int a ) x = a ; void g( ) cout g( ) ; aa1. g( ) ; /pa-f( ); 为什么不行? B *pb = ,【例】(派生类对象中虚函数的调用方法:可通过基类的对象指针、基类

9、的对象引用来调用!注意:调用的是派生类中的虚函数!若派生类中没有重新定义该虚函数,则调用的是上一层基类中的该虚函数, ) # include class A int x ; public: A ( int a ) x = a ; virtual void g( ) cout g( ) ; aa1. g( ) ; /pa-f( ); 为什么不行? B *pb = ,【例】(请注意调用过程。) # include class A int x ; public: A ( int a ) x = a ; virtual void g( ) cout g( ) ; aa1. g( ) ; /pa-f(

10、); 为什么不行? B *pb = ,【例】 (请注意调用过程。) # include class A int x ; public: A ( int a ) x = a ; void g( ) cout g( ) ; aa1. g( ) ; /pa-f( ); 为什么不行? B *pb = ,【例】(注意,若派生类中的某函数只是与虚函数同名,但参数个数或类型有不同时,则属于函数的重载,而不是虚函数!) # include class A int x ; public: A ( int a ) x = a ; virtual void g( ) cout g( ) ; aa1. g( ) ;

11、/pa-f( ); 为什么不行? B *pb = ,【例】(动态多态性的实现:可以让基类的对象指针,先后指向同一类族中不同派生类的对象,这样就可以用相同的调用方式去调用不同派生类对象中的同名虚函数,从而实现动态多态性。) # include class A int x ; public: A ( int a=0 ) x = a ; cout “调用A类构造了!n” ; virtual void show( ) cout “A类 x=” x endl ; ; class B : public A int y ; public: B ( int a=0, int b=0 ) : A( a ) y

12、= b ; cout “调用B类构造了!n” ; void show( ) cout “B类 y=” y endl ; ; class C : public B int z ; public: C( int a=0, int b=0, int c=0 ) : B( a, b ) z = c ; cout “调用C类构造了!n” ; void show( ) cout “C类 z=” z endl ; ;,void main ( ) A a1( 1 ) ; B b1( 20, 30 ) ; C c1( 400, 500, 600 ) ; A *p ; p = ,静态关联、动态关联,关联(绑定、联

13、编):指程序自身彼此关联的过程,即程序中不同部分互相绑定的过程,以确定程序中的各个函数调用式与所执行的相应函数代码的关系,简单的说,关联就是把某个标识符与某个存储地址联系起来。 静态关联(静态绑定、静态联编):指关联(绑定、联编)工作出现在编译阶段。例如,程序中使用对象名来调用成员函数时,在编译阶段系统就能根据对象的类型确定所要调用的是哪一个类的成员函数并进行关联。再如,使用对象名来调用某个类族中的虚函数时,在编译阶段系统也能确定要调用的虚函数属于哪一个类并进行关联。 此外,函数重载和运算符重载也是在编译阶段进行关联的。 动态关联(动态绑定、动态联编):指绑定(联编、关联)工作出现在运行阶段。

14、例如,程序中使用基类的对象指针(或基类的对象引用)来调用某个类族中的虚函数时,只有在程序运行过程中,才能根据其具体指向(或具体引用)该类族中的哪一个类的对象,确定出调用的是哪一个类的虚函数。,静态关联、动态关联,虚函数的动态关联:只有通过基类的对象指针(或基类的对象引用)来调用同一类族中派生类的虚函数时,才属于动态关联!原因是:只有在程序运行过程中,系统才能根据该指针(或该引用)具体指向(或具体引用)的是同一类族中的哪一个派生类的对象,确定出调用的是哪一个派生类的虚函数。 注意: 虚函数与一般成员函数比较,调用时执行速度要慢一些。使用虚函数,系统要有一定的空间和时间开销。 当一个类中有虚函数时

15、,编译系统会为该类构造一个虚函数表,它是一个指针数组,存放该类的每个虚函数的入口地址。 由于虚函数的调用机制是间接实现的,且动态关联是在程序运行阶段,相对会降低程序的运行效率。 但通用性也是程序追求的主要目标之一。 虚函数必须是非静态的成员函数:因为静态成员函数不受限于某个对象。,【例】(分别通过对象名、基类的对象指针去调用派生类的虚函数。) # include class A int x ; public: A ( ) x = 10 ; virtual void show( ) cout show( ) ; p = /此处调用属于动态关联! ,【例】(在成员函数中调用虚函数:关键是分析在调用该成员函数时,其 this 指针是基类的对象指针还是派生类的对象指针! ) # include class A public: virtual void f1( ) cout f2( ); void f2( ) cout f3( ); virtual void f3( ) cout f4( ); virtual void f4( ) cout f5( ); void f5( ) cout f4( ); void f4( ) cout f5( ); void f5( ) cout “B:f5n” ; ; v

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

当前位置:首页 > 办公文档 > PPT模板库 > PPT素材/模板

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