1第四章运算符重载2第四章运算符重载4.1什么是运算符重载4.2运算符重载的方法4.3重载运算符的规则4.4运算符重载函数作为类成员函数和友元函数4.5重载双目运算符4.6重载单目运算符4.7重载流插入运算符和流提取运算符4.8类和其他数据类型的转换34.1什么是运算符重载C++为程序员提供了灵活的手段,让程序员自己定义类,自己设计相应的运算符(必须在已有的运算符基础上设计),使之应用于自己定义的类。与函数重载类似,对已有的运算符赋予新的含义,用一个运算符表示不同功能的运算,这就是运算符重载。实际上,我们在此之前已经使用了运算符重载。如是C++的移位运算符,它又与流对象cout配合作为流插入运算符,这是C++对进行了重载处理。4运算符重载的实质运算符重载是对已有的运算符赋予多重含义。必要性:C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)实现机制将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。编译系统对重载运算符的选择,遵循函数重载的选择原则。5例4.1通过成员函数实现复数的加法。classComplex{private:doublereal;doubleimag;public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexcomplex_add(Complex&c2);voiddisplay();};6ComplexComplex::complex_add(Complex&c2){Complexc;c.real=real+c2.real;c.imag=imag+c2.image;returnc;}voidComplex::display(){cout(real,imagi)endl;}intmain(){Complexc1(3,4),c2(5,-10);Complexc3;c3=c1.complex_add(c2);coutc1=;c1.display();coutc2=;c2.display();coutc1+c2=;c3.display();return0;}7在Complex类中定义了complex_add函数做加法,函数的参数是引用对象,作为一个加数。在函数里定义了临时对象c,两个赋值语句相当于:c.real=this-real+c2.real;c.imag=this-imag+c2.image;在main函数中通过对象c1调用加法函数,上面的语句相当于:c.real=c1.real+c2.real;c.imag=c1.imag+c2.image;能否用+运算符实现复数加法?84.2运算符重载的方法运算符重载的方法是定义一个重载运算符函数,在需要时系统自动调用该函数,完成相应的运算。运算符重载实质上是函数的重载。运算符重载函数的格式是:数据类型operator运算符(形参表){重载处理}数据类型:是重载函数值的数据类型。operator是保留字9规则和限制C++中可以重载除下列运算符外的所有运算符:..*::?:只能重载C++语言中已有的运算符,不可臆造新的。不改变原运算符的优先级和结合性。不能改变操作数个数。经重载的运算符,其操作数中至少应该有一个是的数据类型是类。10两种形式重载为类成员函数。重载为友元函数。11运算符函数声明形式函数类型operator运算符(形参){......}重载为类成员函数时,类本身是一个操作操作数,如果需要另一个操作数由函数的参数提供重载为友元函数时参数个数=原操作数个数,且至少应该有一个自定义的形参。12不能重载的运算符只有5个:.成员运算符.*成员指针运算符::域运算符sizeof长度运算符?:条件运算符重载函数名是由operator和运算符联合组成。复数加法运算符重载函数原型可以是:Complexoperator+(Complex&c2);例4.2重载运算符+,用于两个复数相加。13分析:定义一个复数类,用成员函数实现加号的重载函数。两个复数相加结果仍是复数,所以函数的返回值的类型也是复数类。用成员函数实现运算符重载函数时,调用格式是“对象名.成员名”,此时对象就是一个参与运算的操作数,加法还需要另一个操作数,这个操作数用函数的参数传递,参数的类型就是复数类。而运算结果用函数值返回。14classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexoperator+(Complex&c2);voiddisplay();private:doublereal;doubleimag;};15ComplexComplex::operator+(Complex&c2){Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidComplex::display(){cout(real,imagi)endl;}16intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;coutc1=;c1.display();coutc2=;c2.display();coutc1+c2=;c3.display();return0;}17说明:(1)用运行符重载函数取代了例4.1中的加法成员函数,从外观上看函数体和函数返回值都是相同的。(2)在主函数中的表达式c3=c2+c1取代了例4.1中的c3=c1.complex_add(c2),编译系统将表达式c3=c1+c2解释为c1.operator+(c2)对象c1调用的重载函数operator+,以c2为实参计算两个复数之和。18请考虑在例4.2中能否用一个常量和一个复数相加?如c3=3+c2;//错误应该定义对象:ComplexC1(3.0,0):c3=C1+c2;注意:运算符重载后,其原来的功能仍然保留,编译系统根据运算表达式的上下文决定是否调用运算符重载函数。运算符重载和类结合起来,可以在C++中定义使用方便的新数据类型。194.3重载运算符的规则(1)C++只允许已有的部分运算符实施重载。(2)不能重载的运算符有五个。(3)重载不改变操作数的个数。(4)重载不改变运算符的优先级。(5)运算符重载函数不能带默认值参数。(6)运算符重载函数必须与自定义类型的对象联合使用,其参数至少有一个类对象或类对象引用。(7)C++默认提供=和&运算符重载。20(8)运算符重载函数可以是类成员函数也可以是类的友元函数,还可以是普通函数。(9)C++规定赋值运算符、下标运算符、函数调用运算符必须定义为类的成员函数;而输出流插入、输入流提取、类型转换运算符不能定义为类的成员函数。214.4运算符重载函数作为类成员函数和友元函数在例4.2程序中对运算符+进行了重载,该例将运算符重载函数定义为复数类的成员函数。从该程序中看到运算符重载为成员函数时,带一个类类型的形参,而另一个加数就是对象自己。例4.3将加法运算符重载为适用于复数加法,重载函数作为类的友元函数。22#includeiostream.hclassComplex{public:Complex(){real=0;imag=0;}Complex(doubler){real=r;imag=0;}Complex(doubler,doublei){real=r;imag=i;}friendComplexoperator+(Complex&c1,Complex&c2);voiddisplay();private:doublereal;doubleimag;};23Complexoperator+(Complex&c1,Complex&c2){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}//将调用构造函数voidComplex::display(){cout(real,imagi)endl;}24intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;coutc1=;c1.display();coutc2=;c2.display();coutc1+c2=;c3.display();return0;}25加法运算符重载为友元函数,C++在编译时将表达式c1+c2解释为operator+(c1,c2)即相当于执行以下函数Complexoperator+(Complex&c1,Complex&c2){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}因为普通函数是不能直接访问对象的私有成员,如果普通函数必须访问对象的私有成员,可调用类的公有成员函数访问对象的私有成员。这会降低效率。26使用成员函数重载运算符要求左操作数必须是该类对象如想将一个复数和一个整数相加,运算符重载函数作为成员函数定义如下:ComplexComplex::operator+(int&i){returnComplex(real+i,imag);}注意在运算符+的左侧必须是Complex类对象,程序中可以写成:c3=c2+n不能写成:c3=n+c227如果要求在使用重载运算符时,运算符左侧操作数不是对象,就需要将运算符重载函数定义为友元函数:friendComplexoperator+(int&i,Complex&c){returnComplex(c.real+i,c.imag);}友元函数不要求第一个参数必须是类类型,但是要求实参要与形参一一对应:c3=n+c2//顺序正确c3=c2+n//顺序错误28由于使用友元会破坏类的封装,要尽量将运算符重载函数定义为成员函数。除非有特殊需要,才使用友元函数重载运算符。294.5重载双目运算符双目的意思是运算符左边和右边的操作数均参加运算。如果要重载B为类的成员函数,使之能够实现表达式oprd1Boprd2,其中oprd1为A类对象,则B应被重载为A类的成员函数,形参类型应该是oprd2所属的类型。经重载后,表达式oprd1Boprd2相当于oprd1.operatorB(oprd2)。30例4.4定义一个字符串类String,用来处理不定长的字符串,重载相等、大于、小于关系运算符,用于两个字符串的等于、大于、小于的比较运算。操作数:两个操作数都是字符串类的对象。规则:两个字符串进行比较。将“”、“=”、“”运算重载为字符串类的成员函数。31(1)先建立一个String类#includeiostream.h#includestring.hclassString//String是用户自己指定的类名{public:String(){p=NULL;}String(char*str);voiddisplay();private:char*p;};32String::String(char*str){p=str;}voidString::display(){coutp;}intmain(){Stringstring1(Hello),string2(Book);string1.display();coutendl;string2.display();return0;}33先编写出简单的程序框架,编写和调试都比较方便。构造函数是把定义对象时的实参的地址赋予数据成员p,p是指向实参的指针。程序实现了建立对象、输出字符串对象的功能。程序运行结果分别输出HelloBook(2)有了这个基础后,再增加所需的其他内容,先重载大于运算符。程序如下:34#includeiostream.h#includestring.hcl