《谭浩强《C++程序设计》课件第10章.ppt》由会员分享,可在线阅读,更多相关《谭浩强《C++程序设计》课件第10章.ppt(78页珍藏版)》请在第壹文秘上搜索。
1、第10章 运算符重载10.1 什么是运算符重载10.2 运算符重载的方法10.3 重载运算符的规则10.4 运算符重载函数作为类成员函数和友元函数10.5 重载双目运算符10.6 重载单目运算符10.7 重载流插入运算符和流提取运算符10.8 不同类型数据间的转换10.1 什么是运算符重载所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能。运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。现在要讨论的问题是: 用户能否根据自己的需要对C+已提供的运算符进行重载,赋予它们新的含义,使之一名多用。譬如,能否用“+”号进行两个复数的相加。在C+中
2、不能在程序中直接用运算符“+”对复数进行相加运算。用户必须自己设法实现复数相加。例如用户可以通过定义一个专门的函数来实现复数相加。见例10.1。例10.1 通过函数来实现复数相加。#INCLUDE USING NAMESPACE STD;CLASS COMPLEX /定义COMPLEX类PUBLIC:COMPLEX( )REAL=0;IMAG=0; /定义构造函数COMPLEX(DOUBLE R,DOUBLE I)REAL=R;IMAG=I; /构造函数重载COMPLEX COMPLEX_ADD(COMPLEX &C2); /声明复数相加函数VOID DISPLAY( ); /声明输出函数 P
3、RIVATE:DOUBLE REAL; /实部DOUBLE IMAG; /虚部;COMPLEX COMPLEX COMPLEX_ADD(COMPLEX &C2)COMPLEX C;C.REAL=REAL+C2.REAL;C.IMAG=IMAG+C2.IMAG;RETURN C; VOID COMPLEX DISPLAY( ) /定义输出函数COUT(REAL,IMAGI)ENDL;INT MAIN( )COMPLEX C1(3,4),C2(5,-10),C3; /定义3个复数对象C3=C1.COMPLEX_ADD(C2); /调用复数相加函数COUTC1=; C1.DISPLAY( ); /输
4、出C1的值COUTC2=; C2.DISPLAY( ); /输出C2的值COUTC1+C2=; C3.DISPLAY( ); /输出C3的值RETURN 0;运行结果如下: C1=(3+4I)C2=(5-10I)C1+C2=(8,-6I)结果无疑是正确的,但调用方式不直观、太烦琐,使人感到很不方便。能否也和整数的加法运算一样,直接用加号“+”来实现复数运算呢?如C3=C1+C2;编译系统就会自动完成C1和C2两个复数相加的运算。如果能做到,就为对象的运算提供了很大的方便。这就需要对运算符“+”进行重载。10.2 运算符重载的方法运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算
5、符时,系统就自动调用该函数,以实现相应的运算。也就是说,运算符重载是通过定义函数实现的。运算符重载实质上是函数的重载。重载运算符的函数一般格式如下: 函数类型 OPERATOR 运算符名称 (形参表列) 对运算符的重载处理 例如,想将“+”用于COMPLEX类(复数)的加法运算,函数的原型可以是这样的: COMPLEX OPERATOR+ (COMPLEX& C1,COMPLEX& C2);在定义了重载运算符的函数后,可以说: 函数OPERATOR+重载了运算符+。为了说明在运算符重载后,执行表达式就是调用函数的过程,可以把两个整数相加也想像为调用下面的函数: INT OPERATOR + (
6、INT A,INT B)RETURN (A+B);如果有表达式5+8,就调用此函数,将5和8作为调用函数时的实参,函数的返回值为13。这就是用函数的方法理解运算符。可以在例10.1程序的基础上重载运算符“+”,使之用于复数相加。例10.2 改写例10.1,重载运算符“+”,使之能用于两个复数相加。#INCLUDE USING NAMESPACE STD;CLASS COMPLEXPUBLIC:COMPLEX( )REAL=0;IMAG=0;COMPLEX(DOUBLE R,DOUBLE I)REAL=R;IMAG=I;COMPLEX OPERATOR+(COMPLEX &C2); /声明重载运
7、算符的函数VOID DISPLAY( ); PRIVATE:DOUBLE REAL;DOUBLE IMAG;COMPLEX COMPLEX OPERATOR+(COMPLEX &C2) /定义重载运算符的函数 COMPLEX C;C.REAL=REAL+C2.REAL;C.IMAG=IMAG+C2.IMAG;RETURN C;VOID COMPLEX DISPLAY( ) COUT(REAL,IMAGI)ENDL;INT MAIN( ) COMPLEX C1(3,4),C2(5,-10),C3;C3=C1+C2; /运算符+用于复数运算COUTC1=;C1.DISPLAY( );COUTC2=
8、;C2.DISPLAY( );COUTREAL+C2.REAL,THIS-REAL就是C1.REAL。在10.2节中已说明,在将运算符函数重载为成员函数后,如果出现含该运算符的表达式,如C1+C2,编译系统把它解释为C1.OPERATOR+(C2) 即通过对象C1调用运算符重载函数,并以表达式中第二个参数(运算符右侧的类对象C2)作为函数实参。运算符重载函数的返回值是COMPLEX类型,返回值是复数C1和C2之和(COMPLEX(C1.REAL + C2.REAL,C1.IMAG+C2.IMAG)。运算符重载函数除了可以作为类的成员函数外,还可以是非成员函数。可以将例10.2改写为例10.3。
9、例10.3 将运算符“+”重载为适用于复数加法,重载函数不作为成员函数,而放在类外,作为COMPLEX类的友元函数。#INCLUDE USING NAMESPACE STD;CLASS COMPLEXPUBLIC:COMPLEX( )REAL=0;IMAG=0;COMPLEX(DOUBLE R,DOUBLE I)REAL=R;IMAG=I;FRIEND COMPLEX OPERATOR + (COMPLEX &C1,COMPLEX &C2);/重载函数作为友元函数VOID DISPLAY( ); PRIVATE:DOUBLE REAL;DOUBLE IMAG;COMPLEX OPERATOR
10、+ (COMPLEX &C1,COMPLEX &C2) /定义作为友元函数的重载函数RETURN COMPLEX(C1.REAL+C2.REAL, C1.IMAG+C2.IMAG);VOID COMPLEX DISPLAY( )COUT(REAL,IMAGI)ENDL;INT MAIN( )COMPLEX C1(3,4),C2(5,-10),C3;C3=C1+C2;COUTC1=; C1.DISPLAY( );COUTC2=; C2.DISPLAY( );COUTC1+C2 =; C3.DISPLAY( );与例10.2相比较,只作了一处改动,将运算符函数不作为成员函数,而把它放在类外,在CO
11、MPLEX类中声明它为友元函数。同时将运算符函数改为有两个参数。在将运算符“+”重载为非成员函数后,C+编译系统将程序中的表达式C1+C2解释为OPERATOR+(C1,C2)即执行C1+C2相当于调用以下函数: COMPLEX OPERATOR + (COMPLEX &C1,COMPLEX &C2) RETURN COMPLEX(C1.REAL+C2.REAL, C1.IMAG+C2.IMAG);求出两个复数之和。运行结果同例10.2。为什么把运算符函数作为友元函数呢?因为运算符函数要访问COMPLEX类对象中的成员。如果运算符函数不是COMPLEX类的友元函数,而是一个普通的函数,它是没有
12、权利访问COMPLEX类的私有成员的。在10.2节中曾提到过: 运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数。现在分别讨论这3种情况。首先,只有在极少的情况下才使用既不是类的成员函数也不是友元函数的普通函数,原因是上面提到的,普通函数不能直接访问类的私有成员。在剩下的两种方式中,什么时候应该用成员函数方式,什么时候应该用友元函数方式?二者有何区别呢?如果将运算符重载函数作为成员函数,它可以通过THIS指针自由地访问本类的数据成员,因此可以少写一个函数的参数。但必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算
13、符函数的类型相同。因为必须通过类的对象去调用该类的成员函数,而且只有运算符重载函数返回值与该对象同类型,运算结果才有意义。在例10.2中,表达式C1+C2中第一个参数C1是COMPLEX类对象,运算符函数返回值的类型也是COMPLEX,这是正确的。如果C1不是COMPLEX类,它就无法通过隐式THIS指针访问COMPLEX类的成员了。如果函数返回值不是COMPLEX类复数,显然这种运算是没有实际意义的。如想将一个复数和一个整数相加,如C1+I,可以将运算符重载函数作为成员函数,如下面的形式: COMPLEX COMPLEX OPERATOR+(INT &I) /运算符重载函数作为COMPLEX
14、类的成员函数RETURN COMPLEX(REAL+I,IMAG);注意在表达式中重载的运算符“+”左侧应为COMPLEX类的对象,如C3=C2+I; 不能写成C3=I+C2; /运算符“+”的左侧不是类对象,编译出错如果出于某种考虑,要求在使用重载运算符时运算符左侧的操作数是整型量(如表达式I+C2,运算符左侧的操作数I是整数),这时是无法利用前面定义的重载运算符的,因为无法调用I.OPERATOR+函数。可想而知,如果运算符左侧的操作数属于C+标准类型(如INT)或是一个其他类的对象,则运算符重载函数不能作为成员函数,只能作为非成员函数。如果函数需要访问类的私有成员,则必须声明为友元函数。
15、可以在COMPLEX类中声明: FRIEND COMPLEX OPERATOR+(INT &I,COMPLEX &C); /第一个参数可以不是类对象在类外定义友元函数: COMPLEX OPERATOR+(INT &I, COMPLEX &C) /运算符重载函数不是成员函数RETURN COMPLEX(I+C.REAL,C.IMAG);将双目运算符重载为友元函数时,在函数的形参表列中必须有两个参数,不能省略,形参的顺序任意,不要求第一个参数必须为类对象。但在使用运算符的表达式中,要求运算符左侧的操作数与函数第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。如C3=I+C2; /正确,类
16、型匹配C3=C2+I; /错误,类型不匹配请注意,数学上的交换律在此不适用。如果希望适用交换律,则应再重载一次运算符“+”。如COMPLEX OPERATOR+(COMPLEX &C, INT &I) /此时第一个参数为类对象RETURN COMPLEX(I+C.REAL,C.IMAG);这样,使用表达式I+C2和C2+I都合法,编译系统会根据表达式的形式选择调用与之匹配的运算符重载函数。可以将以上两个运算符重载函数都作为友元函数,也可以将一个运算符重载函数(运算符左侧为对象名的) 作为成员函数,另一个(运算符左侧不是对象名的)作为友元函数。但不可能将两个都作为成员函数,原因是显然的。C+规定,有的运算符(如赋值运算符、下标运算符、函数调用运算符)必须定义为类的成员函数,有的运算符则不能定义为类的成员函数(如流插入“”、类型转换运算符)。由于友元的使用会破坏类的封装,因此从原则上说,要尽量将运算符函数作为成员函数。但考虑到各方面的因素,一般将单目运算符重载为成员函数,将双目运算符重载为友元函数。在学习了本章第10.7节例10.9的讨论后,读者对此会有更深入的认识。说明: 有的C+编译系