c程序设计语言揣锦华第8章多态性

上传人:san****019 文档编号:70778400 上传时间:2019-01-18 格式:PPT 页数:87 大小:524.81KB
返回 下载 相关 举报
c程序设计语言揣锦华第8章多态性_第1页
第1页 / 共87页
c程序设计语言揣锦华第8章多态性_第2页
第2页 / 共87页
c程序设计语言揣锦华第8章多态性_第3页
第3页 / 共87页
c程序设计语言揣锦华第8章多态性_第4页
第4页 / 共87页
c程序设计语言揣锦华第8章多态性_第5页
第5页 / 共87页
点击查看更多>>
资源描述

《c程序设计语言揣锦华第8章多态性》由会员分享,可在线阅读,更多相关《c程序设计语言揣锦华第8章多态性(87页珍藏版)》请在金锄头文库上搜索。

1、第8章 多态性,8.1 多态性概述 8.2 运算符重载 8.3 虚函数 8.4 抽象类,8.1 多态性概述,所谓多态性是指同一个接口可以通过多种方法调用,如图8-1所示。通俗地说,多态性是指用一个相同的名字定义不同的函数,这些函数的执行过程不同,但是有相似的操作,即用同样的接口访问不同的函数。比如,一个对象中有很多求两个数中最大值的行为,虽然可以针对不同的数据类型,写很多不同名称的函数来实现,但事实上,它们的功能几乎完全相同。这时,就可以利用多态的特征,用统一的标识来完成这些功能。,图8-1 多态性为用户提供单一接口示意图,面向对象的多态性从实现的角度来讲,可以分为静态多态性和动态多态性两种。

2、静态多态性是在编译的过程中确定同名操作的具体操作对象的,而动态多态性则是在程序运行 过程中动态地确定操作所针对的具体对象的。这种确定操作具体对象的过程就是联编(binding),也称为绑定。联编是指计算机程序自身彼此关联的过程。也就是把一个标识符名和一个存储地址联系在一起的过程。用面向对象的术语讲,就是把一条消息和一个对象的方法相结合的过程。,所谓消息,是指对类的成员函数的调用。不同的方法是指不同的实现,也就是调用了不同的函数。按照联编进行阶段的不同,联编方法可以分为两种:静态联编和动态联编。这两种联编过程分别对应着多态的两种实现方式。联编工作在编译连接阶段完成的情况称为静态联编。在编译、连接

3、过程中,系统就可以根据类型匹配等特征确定程序中操作调用与执行该操作的代码的关系,即确定某一个同名标识到底是要调用哪一段程序代码。函数重载和运算符重载就属于静态多态性。,和静态联编相对应,如果联编工作在程序运行阶段完成,则称为动态联编。在编译、连接过程中无法解决的联编问题,要等到程序开始运行之后再来确定。例如,本章将要介绍的虚函数就是通过动态联编完成的。 函数重载在函数及类的章节中曾做过详细的讨论,所以在本章中,静态多态性主要介绍运算符重载;对于动态多态性,将对虚函数作详细介绍。,8.2 运算符重载,C+中预定义的运算符的操作对象只能是基本数据类型。实际上,对于很多用户自定义的类型(如类),也需

4、要有类似的运算操作。例如,下面的程序声明了一个点类point。 classpoint /point类声明 private: intx,y;,public: /构造函数 point(intxx=0,intyy=0)x=xx;y=yy; intget_x(); /显示x值 intget_y(); /显示y值 /. ;,于是我们可以这样声明点类的对象: pointp1(1,1),p2(3,3) 如果我们需要对p1和p2进行加法运算,该如何实现呢?我们当然希望能使用“+”运算符,写出表达式“p1+p2”,但是编译的时候却会出错,因为编译器不知道该如何完成这个加法。这时候,我们就需要自己编写程序来说明“

5、+”在作用于point类对象时,该实现什么样的功能,这就是运算符重载。运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时,导致不同类型的行为。,在运算符重载的实现过程中,首先把指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参,然后,根据实参的类型来确定需要调用的函数。这个过程是在编译过程中完成的。,8.2.1 运算符重载的规则 运算符是在C+系统内部定义的,它们具有特定的语法规则,如参数说明、运算顺序、优先级别等。因此,运算符重载时必须要遵守一定的规则。 C+中的运算符除了少数几个(类属关系运算符“.”、作用域分辨符“:”、成员指针运算符“*”

6、、sizeof运算符和三目运算符“?:”)之外,全部可以重载,而且只能重载C+中已有的运算符,不能臆造新的运算符。,重载之后运算符的优先级和结合性都不能改变,也不能改变运算符的语法结构,即单目运算符只能重载为单目运算符,双目运算符只能重载为双目运算符。 运算符重载后的功能应当与原有功能相类似。 重载运算符含义必须清楚,不能有二义性。 运算符的重载形式有两种:重载为类的成员函数和重载为类的友元函数。,运算符重载为类的成员函数的一般语法形式如下: operator(形参表) 函数体; 运算符重载为类的友元函数的一般语法形式如下: friendoperator(形参表) 函数体; ,其中: 函数类型

7、指定了重载运算符的返回值类型,也就是运算结果类型。 operator是定义运算符重载函数的关键字。 运算符是要重载的运算符名称。 形参表给出重载运算符所需要的参数和类型。 friend是对于运算符重载为友元函数时,在函数类型说明之前使用的关键字。,特别需要注意的是,当运算符重载为类的成员函数时,函数的参数个数比原来的操作数个数要少一个(后置“+”、“-”除外);当重载为类的友元函数时,参数个数与原操作数的个数相同。原因是重载为类的成员函数时,如果某个对象使用重载了的成员函数,自身的数据可以直接访问,就不需要再放在参数表中进行传递,少了的操作数就是该对象本身。,8.2.2 运算符重载为成员函数

8、运算符重载实质上就是函数重载,当运算符重载为成员函数之后,它就可以自由地访问本类的数据成员了。实际使用时,总是通过该类的某个对象来访问重载的运算符。如果是双目运算符,一个操作数是对象本身的数据,由this指针指出,另一个操作数则需要通过运算符重载函数的参数表来传递;如果是单目运算符,操作数由对象的this指针给出,就不再需要任何参数。下面分别介绍这两种情况。,1双目运算:oprdlBoprd2 对于双目运算符B,如果要重载B为类的成员函数,使之能够实现表达式oprdlBoprd2(其中oprdl为A类的对象),则应当把B重载为A类的成员函数,该函数只有一个形参,形参的类型是oprd2所属的类型

9、。经过重载之后,表达式oprdlBoprd2就相当于函数调用oprdl.operatorB(oprd2)。,2单目运算 1)前置单目运算:Uoprd 对于前置单目运算符U,如“-”(负号)、“+”等,如果要重载U为类的成员函数,用来实现表达式Uoprd(其中oprd为A类的对象),则U应当重载为A类的成员函数,函数没有形参。经过重载之后,表达式Uoprd相当于函数调用oprd.operatorU()。 例如,前置单目运算符“+”重载的语法形式如下: operator+(); 使用前置单目运算符“+”的语法形式如下: +;,2) 后置单目运算:oprdV 再来看后置运算符V,如“+”和“-”,如

10、果要将它们重载为类的成员函数,用来实现表达式oprd+或oprd-(其中oprd为A类的对象),那么运算符就应当重载为A类的成员函数,这时函数要带有一个整型(int)形参。重载之后,表达式oprd+和oprd-就相当于函数调用oprd.operator+(0)和oprd.operator-(0)。 例如,后置单目运算符“+”重载的语法形式如下: operator+(int); 使用后置单目运算符“+”的语法形式如下: +;,【例8-1】双目运算符重载为成员函数例题。 本例题重载二维点point加减法运算(关于二维点point类的定义在前面章节中已介绍过),将一个双目运算符重载为成员函数。poi

11、nt的加减法是x和y分别相加减,运算符的两个操作数都是point类的对象,因此,可以把“+”、“-”运算符重载为point类的成员函数,重载函数只有一个形参,类型同样也是point类对象。,#include classpoint private: floatx,y; public: point(floatxx=0,floatyy=0)x=xx;y=yy; floatget_x()returnx; floatget_y()returny;,pointoperator+(pointp1); /重载运算符“+” pointoperator-(pointp1); /和“-”为成员函数 ; pointp

12、oint:operator+(pointq) returnpoint(x+q.x,y+q.y); pointpoint:operator-(pointq) returnpoint(x-q.x,y-q.y); voidmain(), pointp1(3,3),p2(2,2),p3,p4; /声明point类的对象 p3=p1+p2; /两点相加 p4=p1-p2; /两点相减 cout“p1+p2:x=“p3.get_x()“,y=“p3.get_y()endl; cout“p1-p2:x=“p4.get_x()“,y=“p4.get_y()endl; ,在本例中,将point的加减法运算重载为

13、point类的成员函数。可以看出,除了在函数声明及实现的时候使用了关键字operator之外,运算符重载成员函数与类的普通成员函数没有什么区别。在使用的时候,可以直接通过运算符、操作数的方式来完成函数调用。这时,运算符“+”、“-”原有的功能都不改变,对整型数、浮点数等基本类型数据的运算仍然遵循C+预定义的规则,同时添加了新的针对point运算的功能。“+”这个运算符,作用于不同的对象就会导致完全不同的操作行为,具有了更广泛的多态特征。,本例中重载的“+”、“-”函数中,都是创建一个临时的无名对象作为返回值: returnpoint(x+q.x,y+q.y); 这表面上看起来像是对构造函数的调

14、用,但其实并非如此。这是临时对象语法,它的含义是创建一个临时对象并返回它。当然,也可以按如下形式返回函数值: pointpoint:operator+(pointq) pointp; p.x=x+q.x;,p.y=y+q.y; returnp; pointpoint:operator-(pointq) pointp; p.x=x-q.x; p.y=y-q.y; returnp; ,这两种方法的执行效率是完全不同的。后者的执行过程是这样的:创建一个局部对象p(这时会调用构造函数),执行return语句时,会调用拷贝构造函数,将p的值拷贝到主调函数中的一个无名临时对象中。当函数operator+结

15、束时,会调用析构函数析构对象p,然后p消亡。两种方法相比,前一种方法的效率高,因为它是直接将一个无名临时对象创建到主调函数中。 例8-1的程序运行结果为 p1+p2:x=5,y=5 p1-p2:x=1,y=1,【例8-2】单目运算符重载为成员函数例题。 本程序为时钟计时程序。在程序中将单目运算符重载为类的成员函数,单目运算符前置“+”和后置“+”的操作数是时钟类的对象,可以把这些运算符重载为时钟类的成员函数。对于前置单目运算符,重载函数没有形参;对于后置单目运算符,重载函数有一个整数形参。本例中,我们把自增前置“+”和自减前置“-”运算重载为point类的成员函数。,#include clas

16、spoint private: floatx,y; public: point(floatxx=0,floatyy=0)x=xx;y=yy; floatget_x()returnx; floatget_y()returny;,pointoperator+(); /重载前置运算符“+” pointoperator-(); /重载前置运算符“-” ; pointpoint:operator+() if(x640)+x; if(y480)+y; return*this; ,pointpoint:operator-() if(x0)-x; if(y0)-y; return*this; voidmain() pointp1(10,10),p2(200,200); /声明point类的对象 for(inti=0;i5;i+

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

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

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