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






