C程序设计教程第13章多态性与虚函数

上传人:大米 文档编号:590407894 上传时间:2024-09-14 格式:PPT 页数:28 大小:119.50KB
返回 下载 相关 举报
C程序设计教程第13章多态性与虚函数_第1页
第1页 / 共28页
C程序设计教程第13章多态性与虚函数_第2页
第2页 / 共28页
C程序设计教程第13章多态性与虚函数_第3页
第3页 / 共28页
C程序设计教程第13章多态性与虚函数_第4页
第4页 / 共28页
C程序设计教程第13章多态性与虚函数_第5页
第5页 / 共28页
点击查看更多>>
资源描述

《C程序设计教程第13章多态性与虚函数》由会员分享,可在线阅读,更多相关《C程序设计教程第13章多态性与虚函数(28页珍藏版)》请在金锄头文库上搜索。

1、C+程序设计湖南大学 杜四春、银红霞第13章多态性与虚函数13.1 普通成员函数重载 13.2 派生类指针 13.3 虚函数 13.4 纯虚函数与抽象类 .C+程序设计湖南大学 杜四春、银红霞多态性是面向对象程序设计的重要特征之一。所谓多态性是指当不同的对象收到相同的消息时,产生不同的动作。C+的多态性具体体现在运行和编译两个方面,在程序运行时的多态性通过继承和虚函数来体现,而在程序编译时多态性体现在函数和运算符的重载上。.C+程序设计湖南大学 杜四春、银红霞13.1 普通成员函数重载在C+语言中,只有在声明函数原型时形式参数的个数或者对应位置的类型不同,两个或更多的函数就可以共用一个名字。这

2、种在同一作用域中允许多个函数使用同一函数名的措施被称为重载overloading)。函数重载是C+程序获得多态性的途径之一。13.1.1函数重载的方法函数重载要求编译器能够唯一地确定调用一个函数时应执行哪个函数代码,既采用哪个函数实现。确定函数实现时,要求从函数参数的个数和类型上来区分。这就是说,进行函数重载时,要求同名函数在参数个数上不同,或者参数类型不同。否则,将无法实现函数重载。.C+程序设计湖南大学 杜四春、银红霞#includeintsquare(intx)returnx*x;doublesquare(doubley)returny*y;main()cout”Thesquareofi

3、nteger7is”square(7)endl;cout”Thesquareofdouble7.5is”square(7.5)endl;return0;例13-1:给出以下程序的运行结果。此程序的运行结果为:Thesquareofinteger7is49Thesquareofinteger7.5is56.25.C+程序设计湖南大学 杜四春、银红霞#includeconstdoublePI=3.1415;doublelength(floatr)return2*PI*r;doublelength(floatx,floaty)return2*(x+y);例13-2:用重载函数实现求圆和矩形的周长。v

4、oidmain()floata,b,r;coutr;cout”圆周长:”length(r)endl;coutab;cout”矩形周长:”length(r)endl;.C+程序设计湖南大学 杜四春、银红霞13.1.2函数重函数重载的表示形式的表示形式普通成普通成员函数重函数重载可表达可表达为两种形式:两种形式:1.在一个在一个类说明中重明中重载例如:例如:Show(int,char);Show(char*,float);2.基基类的的成成员函函数数在在派派生生类重重载。有有3种种编译区分方法区分方法(1根据参数的特征加以区分根据参数的特征加以区分例如:例如:Show(int,char)与与Sho

5、w(char*,float)不是同一函数,不是同一函数,编译能能够区分区分.C+程序设计湖南大学 杜四春、银红霞(2使用“:”加以区分例如:A:Show()有别于B:Show()(3根据类对象加以区分例如:Aobj.Show()调用A:Show()Bobj.Show()调用B:Show().C+程序设计湖南大学 杜四春、银红霞13.1.3 函数重函数重载的注意事的注意事项在在C+语言言中中,编译程程序序选择相相应的的重重载函函数数版版本本时函函数数返返回回值类型型是是不不起起作作用用的的。不不能能仅靠靠函函数数的的返返回回值来来区区别重重载函函数数,必必须从从形式参数上区形式参数上区别开来。例

6、如:开来。例如:void print(int a);void print(int a,int b);int print(float a);这三三个个函函数数是是重重载函函数数,因因为C+编译程程序可以从形式参数上将它序可以从形式参数上将它们区区别开来。开来。.C+程序设计湖南大学 杜四春、银红霞但:intf(inta);doublef(inta);这两个函数就不是重载函数,编译程序认为这是对一个函数的重复说明,因为两个函数的形式参数个数与相应位置的类型完全相同。由typedef定义的类型别名并没有真正创建一个新的类型,所以以下程序段:typedefdoublemoney;doublecalcu

7、late(doubleincome);moneycalculate(moneyincome);也是错误的函数重载。.C+程序设计湖南大学 杜四春、银红霞同样道理,不同参数传递方式也无法区别重载函数,如:voidfunc(intvalue);voidfunc(int&value);也不能作为重载函数。在程序中不可滥用函数重载,不适当的重载会降低程序的可读性。C+语言并没有提供任何约束限制重载函数之间必须有关联,程序员可能用相同的名字定义两个互不相关的函数。实际上函数重载暗示了一种关联,不应该重载那些本质上有区别的函数,只有当函数实现的语义非常相近时才应使用函数重载。.C+程序设计湖南大学 杜四春

8、、银红霞13.1.4 函数重函数重载的二的二义性性函函数数重重载的的二二义性性ambiguity是是指指C+语言言的的编译程程序序无无法法在在多多个个重重载函函数数中中选择正正确确的的函函数数进行行调用用。函函数数重重载的的二二义性性主主要要源源于于C+语言的言的隐式式类型型转换与默与默认参数。参数。在在函函数数调用用时,编译程程序序将将按按以以下下规则选择重重载函函数数:如如果果函函数数调用用的的实际参参数数类型型与与一一个个重重载函函数数形形式式参参数数类型型完完全全匹匹配配,则选择调用用该重重载函函数数;如如果果找找不不到到与与实际参参数数类型型完完全全匹匹配配的的函函数数原原型型,但但

9、如如果果将将一一个个类型型转换为更更高高级类型型后后能能找找到到完完全全匹匹配配的的函函数数原原型型,编译程程序序将将选择调用用该重重载函函数数。所所谓更更高高级类型型是是指指能能处理理的的值域域较大大,如如int转换为unsigned int,unsigned int转换为long,long转换为unsigned float等。等。.C+程序设计湖南大学 杜四春、银红霞例如:intfunc(doubled);countshow_phone();一个指向基类的指针可用来指向从基类公有派生的任何对象,这一事实非常重要,它是C+实现运行时多态的关键途径。.C+程序设计湖南大学 杜四春、银红霞13.

10、3 虚函数13.3.1 虚函数的概念虚函数的概念虚虚函函数数是是在在基基类中中冠冠以以关关键字字 virtual 的的成成员函函数数。它它提提供供了了一一种种接接口口界界面面。虚虚函函数数可可以以在一个或多个派生在一个或多个派生类中被重定中被重定义。 例例13-7 :当当main()函函数数的的语句句16随随着着指指针p所所指指对象象不不同同而而调用用不不同同版版本本的的who()函函数数时,就就实现了了运运行行时的的多多态,这种种机机制制的的实现依依赖于于在在在在基基类中中把把成成员函函数数 who()说明明为虚函数。虚函数。 .C+程序设计湖南大学 杜四春、银红霞在C+语言中,是通过将一个

11、函数定义成虚函数来实现运行时的多态的。如果一个函数被定义为虚函数,那么,即使是使用指向基类对象的指针来调用该成员函数,C+也能保证所调用的是正确的特定于实际对象的成员函数。如果类c1,c2由基类base派生而来,base有一个用virtual修饰的公有或保护函数成员f(),而在c1,c2中的一些类中重新定义了成员函数f(),而对f()的调用都是通过级基类的对象或指针进行的,在程序执行时才决定是调用c1还是c2或其他派生类中定义的f(),这样的函数f()称为虚函数。.C+程序设计湖南大学 杜四春、银红霞一旦一个函数在基类中第一次声明时使用了virtual了关键字,那么,当派生类重载该成员函数时,

12、无论时否使用了virtual关键字,该成员函数都将被看作一个虚函数,也就是说,虚函数的重载函数仍是虚函数。注意:在派生类重定义虚函数时必须有相同的函数原型,包括返回类型,函数名、参数个数、参数类型的顺序必须相同。虚函数必须是类的成员函数。不能为全局函数,也不能为静态函数。不能将友员说明为虚函数,但虚函数可以是另一个类的友员。析构函数可以是虚函数,但构造函数不能为虚函数。.C+程序设计湖南大学 杜四春、银红霞13.3.2使用虚函数使用虚函数时应注意:注意:(1在在类体体系系中中访问一一个个虚虚函函数数时,应使使用用指指向向基基类类型型的的指指针或或对基基类类型型的的引引用用,以以满足足运运行行时

13、多多态性性的的要要求求。当当然然也也可可以以像像调用用普普通通成成员函函数数那那样利利用用对象象名名来来调用用一一个个函函数。数。(2在在派派生生类中中重重新新定定义虚虚函函数数时,必必须保保证该函函数数的的值和和参参数数与与基基类中中的的说明明完完全全一一致致,否否则就就属属于于重重载参参数数不不同同或或是是一一个个错误返回返回值不同)。不同)。(3若若在在派派生生类中中没没有有重重新新定定义虚虚函函数数,则该类的的对象将使用其基象将使用其基类中的虚函数代中的虚函数代码。(4虚虚函函数数必必须是是类的的一一个个成成员函函数数,不不能能是是友友元元,但但它它可可以以是是另另一一个个类的的友友元

14、元。另另外外,虚函数不得是一个静虚函数不得是一个静态成成员。.C+程序设计湖南大学 杜四春、银红霞(5析构函数可以是virtual的虚函数,但构造函数则不得是虚函数。一般地将,若某类中定义有虚函数,则其析构函数也应当说明为虚函数。特别是在析构函数需要完成一些有意义的操作比如释放内存时,尤其应当如此。(6一个类的虚函数仅对派生类中重定义的函数起作用,对其他函数没有影响。在基类中使用虚函数保证了通过指向基类对象的指针调用基类的一个虚函数时,C+系统对该调用进行动态绑定,而使用普通函数则是静态绑定。.C+程序设计湖南大学 杜四春、银红霞13.3.3虚函数与重虚函数与重载函数的比函数的比较(1重重载函

15、函数数要要求求函函数数有有相相同同的的返返回回值类型型和和函函数数名名称称,并并有有不不同同的的参参数数序序列列;而而虚虚函函数数则要要求求这三三项函函数数名名、返返回回值类型型和和参参数数序列完全相同;序列完全相同;(2重重载函函数数可可以以是是成成员函函数数或或友友员函函数数,而虚函数只能是成而虚函数只能是成员函数;函数;(3重重载函函数数的的调用用是是以以所所传递参参数数序序列列的的差差别作作为调用用不不同同函函数数的的依依据据;虚虚函函数数是是根根据据对象的不同去象的不同去调用不同用不同类的虚函数;的虚函数;(4虚虚函函数数在在运运行行时表表现出出多多态功功能能,这是是C+的的精精髓髓

16、;而而重重载函函数数则在在编译时表表现出出多多态性。性。.C+程序设计湖南大学 杜四春、银红霞13.4 纯虚函数与抽象类13.4.1纯虚函数虚函数在在许多多情情况况下下,在在基基类中中不不能能给出出有有意意义的的虚虚函函数数定定义,这时可可以以把把它它说明明成成纯虚虚函函数数,把把它它的的定定义留留给派派生生类来来做做。定定义纯虚虚函函数数的的一般形式一般形式为:class类名名virtual返回返回值类型型函数名函数名(参数表参数表)=0;纯虚虚函函数数是是一一个个在在基基类中中说明明的的虚虚函函数数,它它在在基基类中中没没有有定定义,要要求求任任何何派派生生类都都定定义自自己己的的版版本本

17、。纯虚虚函函数数为各各派派生生类提提供供一一个个公公共共界界面面。由由于于纯虚虚函函数数所所在在的的类中中没没有有它它的的定定义,在在该类的的构构造造函函数数和和析析构构函函数数中中不不允允许调用用纯虚虚函函数数,否否则会会导致致程程序序运运行行错误。但但其其他成他成员函数可以函数可以调用用纯虚函。虚函。.C+程序设计湖南大学 杜四春、银红霞下面的代码在类Creature中将虚函数KindOf声明为纯虚函数:classCreaturepublic:virtualchar*KindOf()=0;char*Creature:KindOf()returnCreature;.C+程序设计湖南大学 杜四

18、春、银红霞使用下面的格式也是可以的:classCreaturepublic:virtualchar*KindOf()=0returnCreature;.C+程序设计湖南大学 杜四春、银红霞13.4.2 抽象抽象类如如果果一一个个类中中至至少少有有一一个个纯虚虚函函数数,那那么么这个个类被被成成为抽抽象象类abstract class)。抽抽象象类中中不不仅包包括括纯虚虚函函数数,也也可可包包括括虚虚函函数数。抽抽象象类中中的的纯虚虚函函数数可可能能是是在在抽抽象象类中中定定义的的,也也可可能能是是从从它它的的抽抽象象基基类中中继承承下下来来且且重重定定义的。的。抽抽象象类有有一一个个重重要要特

19、特点点,即即抽抽象象类必必须用用作作派派生生其其他他类的的基基类,而而不不能能用用于于直直接接创建建对象象实例例。抽抽象象类不不能能直直接接创建建对象象的的原原因因是是其其中中有有一一个个或或多多个个函函数数没没有有定定义,但但仍仍可可使使用用指指向抽象向抽象类的指的指针支持运行支持运行时多多态性。性。 .C+程序设计湖南大学 杜四春、银红霞一个抽象类不可以用来创建对象,这只能用来为派生类提供了一个接口规范,派生类中必须重载基类中的纯虚函数,否则它仍将被看作一个抽象类。如果要直接调用抽象类中定义的纯虚函数,必须使用完全限定名,如上面的示例,要想直接调用抽象类Creature中定义的纯虚函数,应

20、该使用下面的格式:coutCreature:KindOf()endl;上面的代码同时还给出了一种绕过虚函数机制的方法,即使用带有作用域限定符的完全限定函数名。.C+程序设计湖南大学 杜四春、银红霞抽象类只能用作其他类的基类,抽象类不能建立对象。抽象类不能用作函数参数类型、函数返回值类型或显式转换的类型。可以声明抽象类的指针和引用。而且,如果在抽象类的构造函数中调用了纯虚函数,那么,其结果是不确定的。还有,由于抽象类的析构函数可以被声明为纯虚函数,这时,应该至少提供该析构函数的一个实现。一个很好的实现方式是的抽象类中提供一个默认的析构函数,该析构函数保证至少有析构函数的一个实现存在。如下面的例子

21、所示:.C+程序设计湖南大学 杜四春、银红霞classclassname/其他成员public:classname()=0/在此添加析构函数的代码;.C+程序设计湖南大学 杜四春、银红霞由于派生类的析构函数不可能和抽象类的析构函数同名,因而,提供一个默认的析构函数的实现是完全必要的。这也是纯虚析构函数和其他纯虚成员函数的一个最大的不同之处。一般情况下,抽象类的析构函数是有派生类的实现对象释放时由派生类的析构函数隐含的所调用的。抽象类的主要作用是取若干类的共同行为,形成更清晰的概念层次。使用抽象类符合程序设计中的单选原则singlechoiceprinciple)。从基类继承来的纯虚函数,在派生类中仍是虚函数。.

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 工作计划

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