第5章多态性与虚函数PPT课件_第1页
第5章多态性与虚函数PPT课件_第2页
第5章多态性与虚函数PPT课件_第3页
第5章多态性与虚函数PPT课件_第4页
第5章多态性与虚函数PPT课件_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

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

文档简介

1、第第 5 5 章章 多态性与多态性与虚函数虚函数面向对象的面向对象的C+C+程序设计程序设计基础基础本章主要内容本章主要内容 1 多态性多态性 2 虚函数虚函数 3 纯虚函数与抽象类纯虚函数与抽象类多态性的概念多态性的概念多态性n多态性是面向对象的重要特性之一,是指不同多态性是面向对象的重要特性之一,是指不同对象收到相同的消息时产生不同的行为。消息对象收到相同的消息时产生不同的行为。消息是指调用类的成员函数,不同的行为指不同的是指调用类的成员函数,不同的行为指不同的实现,即调用不同的函数;实现,即调用不同的函数;nC+支持两种多态性:编译时的多态性和运行支持两种多态性:编译时的多态性和运行时的

2、多态性;时的多态性;n编译时的多态性是在程序编译过程中确定函数编译时的多态性是在程序编译过程中确定函数操作的具体对象,通过函数重载来实现;运行操作的具体对象,通过函数重载来实现;运行时的多态性是在程序运行过程中才能确定函数时的多态性是在程序运行过程中才能确定函数操作的具体对象,通过虚函数来实现。操作的具体对象,通过虚函数来实现。多态的具体实现多态的具体实现多态性n在面向对象系统中,将确定操作对象在面向对象系统中,将确定操作对象(确定调确定调用哪个函数实现用哪个函数实现)的过程称为联编,即把一条的过程称为联编,即把一条消息(调用类的成员函数)与一个对象的方消息(调用类的成员函数)与一个对象的方法

3、(具体的函数版本)相结合的过程。法(具体的函数版本)相结合的过程。n联编有两种:联编有两种:u静态联编,在编译阶段确定操作的具体对象,静态联编,在编译阶段确定操作的具体对象,也称早期联编、早绑定;也称早期联编、早绑定;u动态联编,在系统运行过程中确定某一操作动态联编,在系统运行过程中确定某一操作对象,也称滞后联编、晚绑定。对象,也称滞后联编、晚绑定。编译时的多态编译时的多态性性编译时的多态是指在编译阶段就编译时的多态是指在编译阶段就决定调用哪个同名函数;决定调用哪个同名函数;通过函数重载来实现。函数重载通过函数重载来实现。函数重载有两种方式:有两种方式:u在一个类中说明的函数重载;在一个类中说

4、明的函数重载;u基类成员函数在派生类中重载。基类成员函数在派生类中重载。多态性 在一个类中说明的函数重载在一个类中说明的函数重载u普通的函数重普通的函数重载:在一个类中载:在一个类中说明的重载函数说明的重载函数靠所带参数的个靠所带参数的个数、参数类型的数、参数类型的不同来区分不同来区分。例子:例子:class Cube public: Cube( ); Cube(int h,int w,int l) height=h; width=w; length=l; private: int height; int width; int length;Cube:Cube( ) height=1; wid

5、th=2; length=3;void main( ) Cube cube1; Cube cube2(4,5,6); 多态性 基类成员函数在派生类中重载基类成员函数在派生类中重载函数名相同,只是它们属于不同的类。如果在派函数名相同,只是它们属于不同的类。如果在派生类中声明了与基类成员函数同名的新函数,则生类中声明了与基类成员函数同名的新函数,则从基类继承的同名函数的所有重载形式都会被覆从基类继承的同名函数的所有重载形式都会被覆盖,即使盖,即使函数的参数表不同函数的参数表不同。区分这种函数的方式有两种:区分这种函数的方式有两种: (1) 使用使用“类名类名:”加以区分加以区分(限定作用域限定作用

6、域); 例:例: Circles:show 和和 Point:show (2) 根据根据对象对象加以区分加以区分; 例:例:Circles Acircle; Point Apoint; Acircle.show( ); Apoint.show( );多态性 基类成员函数在派生类中重载基类成员函数在派生类中重载n例例: 从基类的点类中派生出一个圆类。从基类的点类中派生出一个圆类。基类基类Point中的成员函数中的成员函数area和派生类和派生类Circles中的成员函数中的成员函数area都不带参数,都不带参数,重载时依靠对象来进行区分。重载时依靠对象来进行区分。多态性 基类成员函数在派生类中重

7、载基类成员函数在派生类中重载class Point public: Point(int x,int y) Point:x=x; Point:y=y; float area( ) return 0.0; private: int x; int y; ;class Circles: public Point public: Circles(int x,int y,int ardius):Point(x,y) Circles:radius=radius; float area( ) return 3.1416*radius*radius; private: int radius; ; void ma

8、in( ) Point point1(10,10); Circles circle1(5,5,20); coutpoint1.area( )endl; coutcircle1.area( )endl; coutcircle1.Point:area( )show(); /通过对象指针访问成员函数通过对象指针访问成员函数虚 函 数 引入派生类后的对象指针引入派生类后的对象指针n引入派生类概念后,任何一个被说引入派生类概念后,任何一个被说明为指向基类对象的指针都可以指明为指向基类对象的指针都可以指向它的向它的公有公有派生类派生类;n 指向基类对象的指针,可以指向它指向基类对象的指针,可以指向它的公有

9、派生类的对象,而的公有派生类的对象,而不能指向不能指向它的它的私有派生类的对象私有派生类的对象。虚 函 数 引入派生类后的对象指针引入派生类后的对象指针虚 函 数 不能将一个声明为指向派生类对象的不能将一个声明为指向派生类对象的指针指向其基类的一个对象;指针指向其基类的一个对象; 声明为指向基类对象的指针,当其指声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来访问向公有派生类对象时,只能用它来访问派派生类中从基类继承来的成员生类中从基类继承来的成员,不能访问公,不能访问公有派生类中新添的成员。有派生类中新添的成员。l例例5.1.1:计算和显示研究生和本科生的学费:计算和显示研究生

10、和本科生的学费虚函数的作用虚函数的作用 在例在例5.1.1中,基类中中,基类中calfee( )和和disp( )无无virtual声明,则当指向基类对象的指针声明,则当指向基类对象的指针ptr指向其派生类指向其派生类Graduate对象时,通过对象时,通过ptr只只能访问能访问Graduate中从基类继承下来的成员中从基类继承下来的成员如如calfee( )和和disp( ),而不能访问派生类的,而不能访问派生类的calfee( )和和disp( ) ;虚函数的作用虚函数的作用 给基类给基类calfee( )和和disp( )加上加上virtual声明声明(即虚函数即虚函数)后,当后,当pt

11、r指向其派生类指向其派生类Graduate对象时,调用对象时,调用ptr-calfee( )和和ptr-disp( )时就覆盖了基类的同名函数,调用时就覆盖了基类的同名函数,调用派生类的成员派生类的成员calfee( )和和disp( ); 虚函数的定义,使用户可通过将指向基虚函数的定义,使用户可通过将指向基类对象的指针指向不同的派生类对象,来类对象的指针指向不同的派生类对象,来调用派生类中与基类同名、实现算法不同调用派生类中与基类同名、实现算法不同的函数,实现运行时的多态。的函数,实现运行时的多态。 虚函数的作用虚函数的作用n多态性的实现与联编(或绑定多态性的实现与联编(或绑定binding

12、)有关;有关;n联编是确定函数调用的具体对象的过程,联编是确定函数调用的具体对象的过程,分为静态联编分为静态联编(编译时确定编译时确定)和动态联编和动态联编(运运行时确定行时确定);虚函数的作用虚函数的作用n在上例中有在上例中有“ptr-disp( );”;单凭此语句,;单凭此语句,编译系统无法确定调用那个类对象的函数,编译系统无法确定调用那个类对象的函数,因为编译阶段只作语法检查;因为编译阶段只作语法检查;n到了运行阶段,到了运行阶段,ptr指向哪个对象,就调用哪指向哪个对象,就调用哪个对象的个对象的disp函数。例如函数。例如ptr先指向基类、再先指向基类、再指向派生类指向派生类,那么先后

13、将调用同一类族中,那么先后将调用同一类族中不同类的虚函数;不同类的虚函数;n虚函数是实现动态联编的基础,在运行阶段虚函数是实现动态联编的基础,在运行阶段将虚函数与类对象关联在一起的过程即动态将虚函数与类对象关联在一起的过程即动态联编。联编。虚函数的声明虚函数的声明n虚函数的定义在基类中进行,即在基类虚函数的定义在基类中进行,即在基类中给想定义为虚函数的成员函数声明前中给想定义为虚函数的成员函数声明前加关键词加关键词 virtual ,即:,即:virtual 类型说明符类型说明符 函数名(参数表);函数名(参数表);n基类中的某成员函数被声明为虚函数后,基类中的某成员函数被声明为虚函数后,此虚

14、函数可以在一个或多个派生类中被此虚函数可以在一个或多个派生类中被重新定义;重新定义;n虚函数重新定义时,虚函数重新定义时,不需要不需要virtual声明;声明;虚函数的声明虚函数的声明n在派生类中重新定义虚函数,要求函数原在派生类中重新定义虚函数,要求函数原型包括返回类型、函数名、参数个数、参型包括返回类型、函数名、参数个数、参数类型的顺序,必须与基类中的原型数类型的顺序,必须与基类中的原型完全完全一致一致,仅函数实现不同;,仅函数实现不同;n可通过成员函数调用、指针或引用来访问可通过成员函数调用、指针或引用来访问虚函数;虚函数;n定义一个指向基类对象的指针定义一个指向基类对象的指针ptr,并

15、让,并让它指向同一类族中要调用此虚函数的对象;它指向同一类族中要调用此虚函数的对象;n通过通过ptr调用的虚函数就是调用的虚函数就是ptr指向的对象指向的对象的函数。的函数。例例 :#include class B0/基类基类B0声明声明public:/外部接口外部接口virtual void display( ) /虚成员函数虚成员函数 coutB0:display( )endl; ;class B1: public B0/公有派生公有派生 public: void display( ) coutB1:display( )endl; ;class D1: public B1/公有派生公有派生

16、 public: void display( ) coutD1:display( )display( ); void main( )/主函数主函数 B0 b0, *p;/声明基类对象和指针声明基类对象和指针B1 b1;/声明派生类对象声明派生类对象D1 d1;/声明派生类对象声明派生类对象p=&b0;fun(p);/调用基类调用基类B0函数成员函数成员p=&b1;fun(p);/调用派生类调用派生类B1函数成员函数成员p=&d1;fun(p);/调用派生类调用派生类D1函数成员函数成员运行结果:运行结果:B0:display( )B1:display( )D1:disp

17、lay( )25 虚函数与重载函数的区别虚函数与重载函数的区别函数重载中要求重载函数的参数类型、参数个函数重载中要求重载函数的参数类型、参数个数不同,仅是函数名相同;数不同,仅是函数名相同;虚函数的重定义,要求函数名、返回类型、参虚函数的重定义,要求函数名、返回类型、参数个数、参数类型和顺序都与基类中的函数原数个数、参数类型和顺序都与基类中的函数原型型完全一致完全一致。若不一致,按如下情况处理:。若不一致,按如下情况处理: 1、函数参数相同,函数参数相同,仅返回类型不同仅返回类型不同,作,作出错出错处理;处理; 2、函数参数有差异,函数参数有差异,仅函数名相同仅函数名相同,系统会,系统会将它认

18、为是一般的函数重载,将将它认为是一般的函数重载,将丢失虚特性丢失虚特性。例:例:5.2.2虚 函 数 什么时候使用虚函数?什么时候使用虚函数?如果将某成员函数所在的类作为基类,且如果将某成员函数所在的类作为基类,且该成员函数需要在派生类中重新定义,就该成员函数需要在派生类中重新定义,就将其声明为虚函数;将其声明为虚函数;不要将那些不需要在派生类中重新定义的不要将那些不需要在派生类中重新定义的基类成员函数声明为虚函数;基类成员函数声明为虚函数;如果不是通过指向派生类对象的基类对象如果不是通过指向派生类对象的基类对象指针来访问被声明为虚函数的成员函数,指针来访问被声明为虚函数的成员函数,就不要声明

19、虚函数,因为通过对象访问的就不要声明虚函数,因为通过对象访问的成员函数在编译时就能完全确定。成员函数在编译时就能完全确定。虚 函 数n在类的体系中访问虚函数,可使用指向基类对象的指在类的体系中访问虚函数,可使用指向基类对象的指针或对基类对象的引用,也可以使用对象名直接访问;针或对基类对象的引用,也可以使用对象名直接访问;n派生类中没重新定义虚函数时,该类的对象将使用基派生类中没重新定义虚函数时,该类的对象将使用基类中的虚函数代码(继承下来的);类中的虚函数代码(继承下来的);n虚函数必须是一个类的成员函数,不能是友元函数,虚函数必须是一个类的成员函数,不能是友元函数,但它可以是另一个类的友元成

20、员;但它可以是另一个类的友元成员;n构造函数不能被声明为构造函数不能被声明为virtual,但析构函数可以被声,但析构函数可以被声明为明为virtual;n静态成员函数(不受限于某个对象)和内联函数(不静态成员函数(不受限于某个对象)和内联函数(不在运行中动态确定其位置)不能声明在运行中动态确定其位置)不能声明为为virtual。 虚函数使用注意虚函数使用注意: 虚析构函数虚析构函数n析构函数可以被声明为虚函数,例如:析构函数可以被声明为虚函数,例如: class B public: virtual B( ); ;n 若基类的析构函数声明为虚函数,则由该基类若基类的析构函数声明为虚函数,则由该

21、基类派生的所有派生类的析构函数也都自动成为虚派生的所有派生类的析构函数也都自动成为虚函数,即使派生类的析构函数与基类的析构函函数,即使派生类的析构函数与基类的析构函数不同名;数不同名;n虚函数析构函数的作用:当用虚函数析构函数的作用:当用delete删除对象时,删除对象时,能确保析构函数被正确执行。能确保析构函数被正确执行。 虚析构函数的要点:虚析构函数的要点:n将析构函数声明为虚函数,可以正确地执行析构将析构函数声明为虚函数,可以正确地执行析构函数,即先调用派生类的析构函数,再调用基类函数,即先调用派生类的析构函数,再调用基类的析构函数的析构函数;n当基类的析构函数为虚函数时,无论指针指向同

22、当基类的析构函数为虚函数时,无论指针指向同一类族中的哪个对象,系统都会动态联编,一类族中的哪个对象,系统都会动态联编, 调用调用相应的析构函数,否则系统只会执行基类的析构相应的析构函数,否则系统只会执行基类的析构函数而不执行派生类的析构函数函数而不执行派生类的析构函数;n如果如果delete的操作对象使用了指向派生类对象的基的操作对象使用了指向派生类对象的基类指针,系统就会调用相应类的析构函数;类指针,系统就会调用相应类的析构函数;n一般都将析构函数声明为虚函数,而不管基类是一般都将析构函数声明为虚函数,而不管基类是否需要析构函数。否需要析构函数。n对象指针:指向基类类型的指针可以指对象指针:

23、指向基类类型的指针可以指向其公有派生类对象,但只能访问从基向其公有派生类对象,但只能访问从基类继承的成员;类继承的成员;n虚函数:用于实现滞后联编,在基类中虚函数:用于实现滞后联编,在基类中将成员函数声明为将成员函数声明为virtual特性,就可以特性,就可以在派生类中对该成员函数重新定义(定在派生类中对该成员函数重新定义(定义原型与基类中的完全相同)。当基类义原型与基类中的完全相同)。当基类指针指向派生类时,即可访问派生类重指针指向派生类时,即可访问派生类重新定义的函数,从而实现多态性。新定义的函数,从而实现多态性。虚函数小结虚函数小结本章主要内容本章主要内容 1 多态性多态性 2 虚函数虚

24、函数 3 纯虚函数与抽象类纯虚函数与抽象类n如果基类只表达一些抽象的概念,而不和具体如果基类只表达一些抽象的概念,而不和具体的事物相联系,就不在此基类中定义函数。但的事物相联系,就不在此基类中定义函数。但希望基类必须为它的派生类提供一个公共的界希望基类必须为它的派生类提供一个公共的界面,可以通过在基类中加入面,可以通过在基类中加入纯虚函数纯虚函数(prue virtual function)来实现。来实现。n纯虚函数是一个在基类中说明的虚函数,它纯虚函数是一个在基类中说明的虚函数,它在在该基类中没有定义该基类中没有定义,但要求任何,但要求任何派生类都必须派生类都必须定义定义自己的虚函数版本。纯

25、虚函数自己的虚函数版本。纯虚函数定义形式定义形式:virtual type 函数函数名名(参数表参数表) = 0;n“=0”只表示该成员函数是纯虚的。只表示该成员函数是纯虚的。纯虚函数纯虚函数纯虚 函 数与抽象类例如:例如:#includeclass shape /定义基类定义基类 public: virtual float area ( ) = 0; /定义纯虚函数定义纯虚函数 virtual void Disp( ) = 0; /定义纯虚函数定义纯虚函数;class rectangles:public shape /定义图形的派生类矩形类定义图形的派生类矩形类 public: float

26、area( ); /可以定义可以定义 void Disp( ); /可以定义可以定义; 纯虚函数使用注意:纯虚函数使用注意:n纯虚函数只有函数的名字,不具备函数功能,纯虚函数只有函数的名字,不具备函数功能,不能被调用。只有在派生类中定义以后,它才不能被调用。只有在派生类中定义以后,它才有函数的功能,才可以调用;有函数的功能,才可以调用;n纯虚函数的作用只是在基类中保留一个函数的纯虚函数的作用只是在基类中保留一个函数的名字,以便在派生类中定义它的版本;名字,以便在派生类中定义它的版本;n如果基类中没有保留名字,无法实现多态性;如果基类中没有保留名字,无法实现多态性;n如果在派生类中没有定义纯虚函

27、数的版本,则如果在派生类中没有定义纯虚函数的版本,则该虚函数在派生类中仍然是纯虚函数。该虚函数在派生类中仍然是纯虚函数。抽象类抽象类纯虚函数与抽象类n抽象类:指包含纯虚函数的类。抽象类:指包含纯虚函数的类。n作用作用n抽象类为抽象和设计的目的而声明,将有关的数抽象类为抽象和设计的目的而声明,将有关的数据和行为组织在一个继承层次结构中,保证派生据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。类具有要求的行为。n对于暂时无法实现的函数,可以声明为纯虚函数,对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。留给派生类去实现。n注意注意n抽象类只能作为基类来使用。抽象类只能作为基类来使用。n不能声明抽象类的对象。不能声明抽象类的对象。例例 :纯虚函数与抽象类#include class B0 /抽象基类抽象基类B0声明声明 public: /外部接口外部接口virtual void display( )=0; /纯虚函数成员纯虚函数成员;class B1: public B0 /公有派生公有派生 public:void display( )coutB1:display()endl; /虚成员函数虚成员函数;class D1: public B1 /公有派生公有派生 public:void display( )cout

温馨提示

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

评论

0/150

提交评论