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

下载本文档

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

文档简介

多态性与虚函数

1普通成员函数重载

2派生类指针

3虚函数

4纯虚函数与抽象类

编辑课件 多态性是面向对象程序设计的重要特征之一。所谓多态性是指当不同的对象收到相同的消息时,产生不同的动作。C++的多态性具体表达在运行和编译两个方面,在程序运行时的多态性通过继承和虚函数来表达,而在程序编译时多态性表达在函数和运算符的重载上。编辑课件1普通成员函数重载 在C++语言中,只有在声明函数原型时形式参数的个数或者对应位置的类型不同,两个或更多的函数就可以共用一个名字。这种在同一作用域中允许多个函数使用同一函数名的措施被称为重载〔overloading〕。函数重载是C++程序获得多态性的途径之一。1.1函数重载的方法 函数重载要求编译器能够唯一地确定调用一个函数时应执行哪个函数代码,既采用哪个函数实现。确定函数实现时,要求从函数参数的个数和类型上来区分。这就是说,进行函数重载时,要求同名函数在参数个数上不同,或者参数类型不同。否那么,将无法实现函数重载。编辑课件#include<iostream.h>intsquare(intx){returnx*x;}doublesquare(doubley){returny*y;}main(){cout<<〞Thesquareofinteger7is〞<<square(7)<<endl;cout<<〞Thesquareofdouble7.5is〞<<square(7.5)<<endl;return0;}例1:给出以下程序的运行结果。此程序的运行结果为:Thesquareofinteger7is49Thesquareofinteger7.5is56.25

编辑课件#include<iostream.h>constdoublePI=3.1415;doublelength(floatr){return2*PI*r;}doublelength(floatx,floaty){return2*(x+y);}例2:用重载函数实现求圆和矩形的周长。voidmain(){floata,b,r;cout<<〞输入圆半径:〞;cin>>r;cout<<〞圆周长:〞<<length(r)<<endl;cout<<〞输入矩形长和宽:〞;cin>>a>>b;cout<<〞矩形周长:〞<<length(r)<<endl;}编辑课件1.2函数重载的表示形式 普通成员函数重载可表达为两种形式: 1.在一个类说明中重载 例如: Show(int,char); Show(char*,float); 2.基类的成员函数在派生类重载。有3种编译区分方法 〔1〕根据参数的特征加以区分 例如: Show(int,char)与 Show(char*,float)不是同一函数,编译能够区分编辑课件 〔2〕使用“::〞加以区分 例如: A::Show() 有别于 B::Show() 〔3〕根据类对象加以区分 例如: Aobj.Show()调用 A::Show() Bobj.Show()调用 B::Show()编辑课件1.3函数重载的本卷须知 在C++语言中,编译程序选择相应的重载函数版本时函数返回值类型是不起作用的。不能仅靠函数的返回值来区别重载函数,必须从形式参数上区别开来。例如: voidprint(inta); voidprint(inta,intb); intprint(floata[]); 这三个函数是重载函数,因为C++编译程序可以从形式参数上将它们区别开来。编辑课件 但: intf(inta); doublef(inta); 这两个函数就不是重载函数,编译程序认为这是对一个函数的重复说明,因为两个函数的形式参数个数与相应位置的类型完全相同。 由typedef定义的类型别名并没有真正创立一个新的类型,所以以下程序段: typedefdoublemoney; doublecalculate(doubleincome); moneycalculate(moneyincome); 也是错误的函数重载。编辑课件 同样道理,不同参数传递方式也无法区别重载函数,如: voidfunc(intvalue); voidfunc(int&value); 也不能作为重载函数。 在程序中不可滥用函数重载,不适当的重载会降低程序的可读性。C++语言并没有提供任何约束限制重载函数之间必须有关联,程序员可能用相同的名字定义两个互不相关的函数。实际上函数重载暗示了一种关联,不应该重载那些本质上有区别的函数,只有当函数实现的语义非常相近时才应使用函数重载。

编辑课件1.4函数重载的二义性 函数重载的二义性〔ambiguity〕是指C++语言的编译程序无法在多个重载函数中选择正确的函数进行调用。函数重载的二义性主要源于C++语言的隐式类型转换与默认参数。 在函数调用时,编译程序将按以下规那么选择重载函数:如果函数调用的实际参数类型与一个重载函数形式参数类型完全匹配,那么选择调用该重载函数;如果找不到与实际参数类型完全匹配的函数原型,但如果将一个类型转换为更高级类型后能找到完全匹配的函数原型,编译程序将选择调用该重载函数。所谓更高级类型是指能处理的值域较大,如int转换为unsignedint,unsignedint转换为long,long转换为unsignedfloat等。编辑课件 例如:intfunc(doubled); … count<<func(‘A’); 虽未声明函数原型intfunc〔char〕,但函数调用func〔‘A’〕并不会产生任何问题,因为编译程序自动将字符‘A’转换为double类型,然后调用函数intfunc〔double〕。 隐式类型转换是由C++编译程序自动完成的,这种类型转换是引起函数重载二义性的主要原因。在重载函数中使用默认参数也可能造成二义性。 C++还提供了一种更为灵活的多态性机制:虚函数。虚函数允许函数调用与函数体的联系在运行时才进行。当一般的类型对应于不同的类型变种时,这个能力显得尤其重要。编辑课件2派生类指针 指向基类和派生类的指针是相关的。 例如: A*p; //指向类型A的对象的指针 AA_obj; //类型A的对象 BB_obj; //类型B的对象 p=&A_obj; //p指向类型A的对象 p=&B_obj; //p指向类型B的对象, //它是A的派生类 利用p,可以通过B_obj访问所有从A_obj继承的元素,但不能用p访问B_obj自身特定的元素〔除非用了显式类型转换〕。编辑课件 例6 注意:可以用一个指向基类的指针指向其公有派生类的对象。但却不能用指向派生类的指针指向一个基类对象。希望用基类指针访问其公有派生类的特定成员,必须将基类指针用显式类型转换为派生类指针。例如〔〔B_class*〕p〕->show_phone〔〕;一个指向基类的指针可用来指向从基类公有派生的任何对象,这一事实非常重要,它是C++实现运行时多态的关键途径。编辑课件3虚函数3.1虚函数的概念 虚函数是在基类中冠以关键字virtual的成员函数。它提供了一种接口界面。虚函数可以在一个或多个派生类中被重定义。 例13-7:当main〔〕函数的语句1~6随着指针p所指对象不同而调用不同版本的who〔〕函数时,就实现了运行时的多态,这种机制的实现依赖于在在基类中把成员函数who〔〕说明为虚函数。编辑课件 在C++语言中,是通过将一个函数定义成虚函数来实现运行时的多态的。如果一个函数被定义为虚函数,那么,即使是使用指向基类对象的指针来调用该成员函数,C++也能保证所调用的是正确的特定于实际对象的成员函数。 如果类c1,c2…由基类base派生而来,base有一个用virtual修饰的公有或保护函数成员f〔〕,而在c1,c2…中的一些类中重新定义了成员函数f〔〕,而对f〔〕的调用都是通过级基类的对象或指针进行的,在程序执行时才决定是调用c1还是c2或其他派生类中定义的f〔〕,这样的函数f〔〕称为虚函数。编辑课件 一旦一个函数在基类中第一次声明时使用了virtual了关键字,那么,当派生类重载该成员函数时,无论时否使用了virtual关键字,该成员函数都将被看作一个虚函数,也就是说,虚函数的重载函数仍是虚函数。 注意:在派生类重定义虚函数时必须有相同的函数原型,包括返回类型,函数名、参数个数、参数类型的顺序必须相同。虚函数必须是类的成员函数。不能为全局函数,也不能为静态函数。不能将友员说明为虚函数,但虚函数可以是另一个类的友员。析构函数可以是虚函数,但构造函数不能为虚函数。编辑课件3.2使用虚函数时应注意: 〔1〕在类体系中访问一个虚函数时,应使用指向基类类型的指针或对基类类型的引用,以满足运行时多态性的要求。当然也可以像调用普通成员函数那样利用对象名来调用一个函数。 〔2〕在派生类中重新定义虚函数时,必须保证该函数的值和参数与基类中的说明完全一致,否那么就属于重载〔参数不同〕或是一个错误〔返回值不同〕。 〔3〕假设在派生类中没有重新定义虚函数,那么该类的对象将使用其基类中的虚函数代码。 〔4〕虚函数必须是类的一个成员函数,不能是友元,但它可以是另一个类的友元。另外,虚函数不得是一个静态成员。编辑课件 〔5〕析构函数可以是virtual的虚函数,但构造函数那么不得是虚函数。一般地将,假设某类中定义有虚函数,那么其析构函数也应当说明为虚函数。特别是在析构函数需要完成一些有意义的操作——比方释放内存时,尤其应当如此。 〔6〕一个类的虚函数仅对派生类中重定义的函数起作用,对其他函数没有影响。在基类中使用虚函数保证了通过指向基类对象的指针调用基类的一个虚函数时,C++系统对该调用进行动态绑定,而使用普通函数那么是静态绑定。编辑课件3.3虚函数与重载函数的比较 〔1〕重载函数要求函数有相同的返回值类型和函数名称,并有不同的参数序列;而虚函数那么要求这三项〔函数名、返回值类型和参数序列〕完全相同; 〔2〕重载函数可以是成员函数或友员函数,而虚函数只能是成员函数; 〔3〕重载函数的调用是以所传递参数序列的差异作为调用不同函数的依据;虚函数是根据对象的不同去调用不同类的虚函数; 〔4〕虚函数在运行时表现出多态功能,这是C++的精髓;而重载函数那么在编译时表现出多态性。编辑课件4纯虚函数与抽象类4.1纯虚函数 在许多情况下,在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。定义纯虚函数的一般形式为:class类名{

virtual返回值类型函数名(参数表)=0;

}; 纯虚函数是一个在基类中说明的虚函数,它在基类中没有定义,要求任何派生类都定义自己的版本。纯虚函数为各派生类提供一个公共界面。由于纯虚函数所在的类中没有它的定义,在该类的构造函数和析构函数中不允许调用纯虚函数,否那么会导致程序运行错误。但其他成员函数可以调用纯虚函。编辑课件 下面的代码在类Creature中将虚函数KindOf声明为纯虚函数:classCreature{

public:

virtualchar*KindOf()=0;};char*Creature::KindOf(){

return"Creature";}编辑课件 使用下面的格式也是可以的:classCreature{

public:

virtualchar*KindOf()=0

{

return"Creature";

}};编辑课件4.2抽象类 如果一个类中至少有一个纯虚函数,那么这个类被成为抽象类〔abstractclass〕。抽象类中不仅包括纯虚函数,也可包括虚函数。抽象类中的纯虚函数可能是在抽象类中定义的,也可能是从它的抽象基类中继承下来且重定义的。 抽象类有一个重要特点,即抽象类必须用作派生其他类的基类,而不能用于直接创立对象实例。抽象类不能直接创立对象的原因是其中有一个或多个函数没有定义,但仍可使用指向抽象类的指针支持运行时多态性。编辑课件 一个抽象类不可以用来创立对象,这只能用来为派生类提供了一个接口标准,派生类中必须重载基类中的纯虚函数,否那么它仍将被看作一个抽象类。如果要直接调用抽象类中定义的纯虚函数,必须使用完全限定名,如上面的例如,要想直接调用抽象类Creature中定义的纯虚函数,应该使用下面的格式: cout<<pCreature->Creature::Kin

温馨提示

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

最新文档

评论

0/150

提交评论