《第4章运算符重载》由会员分享,可在线阅读,更多相关《第4章运算符重载(44页珍藏版)》请在金锄头文库上搜索。
1、第第4章章 运算符重载运算符重载 4.1 什么是运算符重载什么是运算符重载4.2 运算符重载的方法运算符重载的方法4.3 重载运算符的规则重载运算符的规则4.4 运算符重载函数作为类成员函数和运算符重载函数作为类成员函数和 友元函数友元函数4.5 重载双目运算符重载双目运算符4.6 重载单目运算符重载单目运算符4.7 重载流插入运算符和流提取运算符重载流插入运算符和流提取运算符14.1 什么是运算符重载什么是运算符重载对已有的运算符赋予新的含义,用一个对已有的运算符赋予新的含义,用一个运算符表示不同功能的运算,这就是运算符表示不同功能的运算,这就是运运算符重载算符重载。运算符重载的本质:对已有
2、的运算符赋运算符重载的本质:对已有的运算符赋予多重含义。予多重含义。2class Complex public: Complex()real=0;imag=0; Complex(double r,double i)real=r;imag=i; Complex complex_add(Complex &c2); void display(); private: double real; double imag; ;例例4.1 通过成员函数实现复数的加法通过成员函数实现复数的加法3Complex Complex:complex_add(Complex &c2) Complex c; c.real=
3、real +c2.real; c.imag=imag+c2.image; return c; void Complex:display()cout(real,imagi)endl;int main() Complex c1(3,4),c2(5,-10),c3; c3=plex_add(c2); coutc1=; c1.display(); coutc2=; c2.display(); coutc1+c2=; c3.display(); return 0;4运算符重载的方法运算符重载的方法:定义一个重载运算符:定义一个重载运算符的函数的函数,在需要时系统自动调用该函数,在需要时系统自动调用该函数
4、,完成相应的运算。完成相应的运算。运算符重载实质上是函数的重载。运算符重载实质上是函数的重载。运算符重载函数的格式是:运算符重载函数的格式是: 函数函数类型类型 operator 运算符运算符名名(形参形参) 对对运算符的重载处理运算符的重载处理 4.2 运算符重载的方法运算符重载的方法5class Complexpublic: Complex()real=0;imag=0; Complex(double r,double i) real=r;imag=i; Complex operator+(Complex &c2); void display(); private: double real
5、; double imag;例例4.2 重载运算符重载运算符+,用于两个复数相加。,用于两个复数相加。函数名函数名6Complex 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; 7int main() Complex c1(3,4),c2(5,-10),c3; c3=c1+c2; coutc1=;c1.display(); coutc2=;c2.display()
6、; coutc1+c2=;c3.display(); return 0;等价于等价于c1.operator+(c2)8 必要性必要性sC+中预定义的运算符其运算对象只能中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定是基本数据类型,而不适用于用户自定义类型义类型(如类如类) 实现机制实现机制s将指定的运算表达式转化为对运算符函将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数数的调用,运算对象转化为运算符函数的实参。的实参。4.2 运算符重载的方法运算符重载的方法9运算符重载的好处:运算符重载和类结合运算符重载的好处:运算符重载和类结合起来,可以在起来,可以在
7、C+中定义出有实际意义中定义出有实际意义而使用方便的新的数据类型。而使用方便的新的数据类型。M注意:运算符被重载后,其原来的功能仍注意:运算符被重载后,其原来的功能仍然保留,编译系统根据运算表达式的上下然保留,编译系统根据运算表达式的上下文决定是否调用运算符重载函数。文决定是否调用运算符重载函数。4.2 运算符重载的方法运算符重载的方法101.C+不允许用户自己定义新的运算符,不允许用户自己定义新的运算符,只允许对已有的部分运算符进行重载。只允许对已有的部分运算符进行重载。2.不能重载的运算符只有不能重载的运算符只有5个:个:. 成员运算符成员运算符.* 成员指针运算符成员指针运算符: 域运算
8、符域运算符sizeof 长度运算符长度运算符?: 条件运算符条件运算符3.重载不能改变运算符操作数的个数。重载不能改变运算符操作数的个数。4.3 重载运算符的规则重载运算符的规则114.重载不能改变运算符的优先级。重载不能改变运算符的优先级。5.重载不能改变运算符的结合性。重载不能改变运算符的结合性。6.重载运算符的函数不能有默认的参数。重载运算符的函数不能有默认的参数。7.运算符重载函数必须和用户定义的自定运算符重载函数必须和用户定义的自定义类型的对象一起使用,其参数至少有义类型的对象一起使用,其参数至少有一个类对象或类对象的引用。一个类对象或类对象的引用。4.3 重载运算符的规则重载运算符
9、的规则128.用于类对象的运算符一般必须重载,用于类对象的运算符一般必须重载,但是运算符但是运算符 = 和和 & 除外。除外。9.应当使重载运算符的功能类似于该运应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的算符作用于标准类型数据时所实现的功能。功能。10.运算符重载函数可以是类运算符重载函数可以是类的成员函数,的成员函数,也可以是类的友元函数也可以是类的友元函数,还可以是普,还可以是普通函数。通函数。4.3 重载运算符的规则重载运算符的规则13重载为类成员函数时重载为类成员函数时参数个数参数个数=原操作数个数原操作数个数-1重载为友元函数时重载为友元函数时 参数个数参数个数
10、=原操作数个数原操作数个数 且至少应该有一个自定义类型的形参且至少应该有一个自定义类型的形参例例4.3 将加法运算符重载为适用于复数加将加法运算符重载为适用于复数加法,重载函数作为类的友元函数。法,重载函数作为类的友元函数。4.4 运算符重载函数作为类成员函数和友元函数运算符重载函数作为类成员函数和友元函数14#include class Complex public: Complex () real=0;imag=0; Complex (double r) real=r;imag=0; Complex (double r,double i) real=r;imag=i; friend Com
11、plex operator+ (Complex &c1, Complex &c2); void display(); private: double real; double imag;15Complex operator+(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.displa
12、y(); coutc2=; c2.display(); coutc1+c2=; c3.display(); return 0;等价于等价于c3=operator+(c1,c2)16如想将一个复数和一个整数相加,运算符如想将一个复数和一个整数相加,运算符重载函数作为成员函数定义如下:重载函数作为成员函数定义如下:Complex Complex :operator+(int & i)return Complex(real+i , imag);注意在运算符注意在运算符+的左侧必须是的左侧必须是Complex类对象,程序中可以写成:类对象,程序中可以写成: c3 = c2 + i;不能写成:不能写成:
13、c3 = i + c2;什么时候用成员函数或友元函数什么时候用成员函数或友元函数17如果要求在使用重载运算符时,运算符左如果要求在使用重载运算符时,运算符左侧操作数不是对象,就不能使用前面定义侧操作数不是对象,就不能使用前面定义的运算符重载函数,可以将运算符重载函的运算符重载函数,可以将运算符重载函数定义为友元函数:数定义为友元函数:friend Complex operator+(int&i,Complex&c) return Complex( c.real+i , c.imag) ;友元函数不要求第一个参数必须是类类型,友元函数不要求第一个参数必须是类类型,但是要求实参要与形参一一对应:但
14、是要求实参要与形参一一对应:c3 = i + c2; /okc3 = c2 +i; /error什么时候用成员函数或友元函数什么时候用成员函数或友元函数18为了实现加法的交换率,必须定义两个运算符重为了实现加法的交换率,必须定义两个运算符重载函数,记住成员函数要求运算符左侧的操作数载函数,记住成员函数要求运算符左侧的操作数必须是自定义类型的对象,而友元函数没有这个必须是自定义类型的对象,而友元函数没有这个限制,可以用下面两个组合中任意一个:限制,可以用下面两个组合中任意一个:成员函数成员函数(左操作数是对象,右操作数是非对象左操作数是对象,右操作数是非对象)、友、友元函数元函数(左操作数是非对
15、象,右操作数是对象左操作数是非对象,右操作数是对象)友元函数友元函数(左操作数是对象,右操作数是非对象左操作数是对象,右操作数是非对象)、友、友元函数元函数(左操作数是非对象,右操作数是对象左操作数是非对象,右操作数是对象)什么时候用成员函数或友元函数什么时候用成员函数或友元函数194.5 重载双目运算符重载双目运算符双目的意思是运算符左边和右边的操作数双目的意思是运算符左边和右边的操作数均参加运算。均参加运算。例例4.4 定义一个字符串类定义一个字符串类String,用来,用来处理不定长的字符串,重载相等、大于、处理不定长的字符串,重载相等、大于、小于关系运算符,用于两个字符串的等于、小于关
16、系运算符,用于两个字符串的等于、大于、小于的比较运算。大于、小于的比较运算。20#include using namespace std;class String public:String() p=NULL; String( char *str ) ;void display(); private:char *p;(1)先建立一个先建立一个String类类21String:String(char *str)p=str;void String:display()coutp;int main() String string1(Hello),string2(Book); string1.displ
17、ay(); cout部分。部分。#include class String public: String () p=NULL; String (char *str); friend bool operator(String &string1,String &string2);private: char *p;String:String(char *str) p=str; 23void String:display() cout(String &string1,String &string2) if(strcmp(string1.p,string2.p)0) return true; else
18、return false; int main() String string1(Hello),string2(Book); coutstring2)endl; return 0;24(3)扩展到对三个运算符重载扩展到对三个运算符重载#include class String public: String()p=NULL; String(char *str); friend bool operator(String &string1, String &string2); friend bool operator(String &string1, String &string2); friend
19、bool operator=(String &string1, String &string2); void display(); private: char *p; ;25String:String(char *str) p=str;void String:display()cout(String &string1,String &string2) if(strcmp(string1.p,string2.p)0) return true; else return false; 26bool operator(String &string1,String &string2)if(strcmp(
20、string1.p,string2.p)0) return true; else return false;bool operator=(String &string1,String &string2) if(strcmp(string1.p,string2.p)=0)return true; elsereturn false;27int main()String string1(Hello),string2(Book), string3(Computer); coutstring2)endl; cout(string1string3)endl; cout(string1=string2)en
21、dl; return 0;运行结果为运行结果为100284.6 重载单目运算符重载单目运算符单目运行符只单目运行符只有有一个操作数,由于只有一一个操作数,由于只有一个操作数,重载函数最多只有一个参数,个操作数,重载函数最多只有一个参数,如果将运算符重载函数定义为成员函数还如果将运算符重载函数定义为成员函数还可以可以省略此省略此参数。参数。例例4.5 有一个有一个Time类,类,包含包含数据成员数据成员minute和和sec,模拟秒表,每次走一秒,模拟秒表,每次走一秒,满满60秒进秒进一分钟一分钟,此时此时秒又从秒又从0开始计数。开始计数。要求要求输出分和秒的值。输出分和秒的值。29#inclu
22、de using namespace std;class Time public: Time()minute=0;sec=0; Time(int m,int s):minute(m),sec(s) Time operator+( ); void display() coutminute:sec=60) sec-=60; +minute; return *this;int main()Time time1(34,0); for (int i=0;i61;i+) + time1; time1.display(); return 0;31C+中除了有前置中除了有前置+外,还有后置外,还有后置+,怎样
23、区分前置,怎样区分前置+和后置和后置+?C+约定,如果自增约定,如果自增(自减自减)运算符重载运算符重载函数中,增加一个函数中,增加一个int型形参,就是后置型形参,就是后置自增自增(自减自减)运算符函数。运算符函数。例例4.6 在例在例4.5的基础上增加对后置自增的基础上增加对后置自增运算符的重载。运算符的重载。32#include using namespace std;class Time public: Time()minute=0;sec=0; Time(int m,int s):minute(m),sec(s) Time operator+(); Time operator+(in
24、t); void display() coutminute:sec=60) sec-=60; +minute; return *this;Time Time:operator+(int) Time temp(*this); /保存修改前的对象做返回值保存修改前的对象做返回值 sec+; if(sec=60) sec-=60; +minute; return temp;34int main()Time time1(34,59),time2; cout time1 : ; time1.display(); +time1; cout+time1: ; time1.display(); time2 =
25、 time1+; couttime1+: ; time1.display(); cout和和运算符进行了重运算符进行了重载,载,使使之作为流提取运算符和流插入运算符,之作为流提取运算符和流插入运算符,用来输入和输出用来输入和输出C+标准类型的数据,标准类型的数据,因此因此要要用用#include 把头文件包含到把头文件包含到程序中。程序中。用户自定义类型的数据不能直接用用户自定义类型的数据不能直接用输输出和输入,如想用它们进行输入或输出,程序出和输入,如想用它们进行输入或输出,程序员必须对它们重载。员必须对它们重载。4.7重载流插入运算符和流提取运算符重载流插入运算符和流提取运算符36重载函数
26、原型的格式如下:重载函数原型的格式如下:istream & operator(istream&,自定自定义类义类&);ostream & operator重载函数和重载函数和重载函数只能重载函数只能定义为友元函数,不能定义为成员函数。定义为友元函数,不能定义为成员函数。因为函数有两个形参,并且第一个形参不是自因为函数有两个形参,并且第一个形参不是自定义类型。定义类型。4.7重载流插入运算符和流提取运算符重载流插入运算符和流提取运算符37例例4.7 在例在例4.2的基础上,用重载的的基础上,用重载的输出复数。输出复数。在类中声明在类中声明重载函数是友元函数重载函数是友元函数friend ostr
27、eam& operator(ostream&,Complex&);在类外定义友元函数:在类外定义友元函数:ostream& operator(ostream& output,Complex& c) output(c.real+ c.imagi)endl; return output;4.7.1重载流插入运算符重载流插入运算符 38#include int main() Complex c1(2,4),c2(6,10),c3; c3=c1+c2; coutc3; return 0;operator(cout, c3);coutc3c2; 如何处理?如何处理?coutc35endl;区分区分例例4
28、.8在例在例4.7的基础上,增加重载流提取运算符的基础上,增加重载流提取运算符,用,用cin输入复数输入复数在类中声明友元函数:在类中声明友元函数:friend istream& operator (istream&,Complex&);在类外定义函数:在类外定义函数:istream& operator (istream& input,Complex& c) coutc.realc.imag; return input;40int main() Complex c1,c2; cinc1c2; coutc1=c1endl; coutc2=c2endl; return 0; 输入的虚部是负数时,输
29、出的形式变成:输入的虚部是负数时,输出的形式变成: c2 = ( 4+ - 10i )ostream& operator(ostream& output,Complex& c) output(= 0) output + ; output c.imagi)endl; return output;414.8 不同类型数据间的转换不同类型数据间的转换4.8.1 标准类型数据间的转换标准类型数据间的转换1.隐式类型转换隐式类型转换 int i = 6;i = 7.5 + i;2.显式类型转换显式类型转换类型名类型名(数据数据); int(89.5);C语言:语言:(int)89.5;424.8 不同类
30、型数据间的转换不同类型数据间的转换4.8.2 用转换构造函数进行类型转换用转换构造函数进行类型转换 转换构造函数的作用转换构造函数的作用s将一个其他类型的数据转换成一个指定的类的将一个其他类型的数据转换成一个指定的类的对象。对象。 转换构造函数的形式转换构造函数的形式类名类名(指定类型的数据指定类型的数据) Complex(double x)real=r;imag=0;M转换构造函数只能有一个参数。转换构造函数只能有一个参数。434.8 不同类型数据间的转换不同类型数据间的转换4.8.3 用类型转换函数进行类型转换用类型转换函数进行类型转换类型转换函数的作用类型转换函数的作用s将一个类的对象转换成另一类型的数据。将一个类的对象转换成另一类型的数据。类型转换函数的形式类型转换函数的形式operator 类型名类型名()实现转换的语句实现转换的语句M在在operator前不能指定函数类型,函数前不能指定函数类型,函数没有参数。没有参数。M类型转换函数只能作为成员函数。类型转换函数只能作为成员函数。44