您好,欢迎访问三七文档
运算符重载•绝大多数编程语言(如C、VBJava等)的运算符只能操作基本类型的数据,而不能操作自定义类型的数据。•若希望运算符也能直接操作自定义类型的数据(如复数对象),如何实现?•答:重载C++的运算符。•运算符重载通过函数重载来实现,体现的是编译时的多态性,增强了C++语言的可扩展性和自然理解性。1运算符重载•目的:使运算符直接操作自定义类型的数据。#includeiostreamusingnamespacestd;classComplex{floatreal,image;public:Complex(floatr=0,floati=0){real=r;image=i;}Complexadd(constComplex&c){returnComplex(real+c.real,image+c.image);}};intmain(){Complexc1(3.2,4.6),c2(6.2,8.7),c3;c3=c1.add(c2);return0;};•问:能否简写成c3=c1+c2;•答:运算符虽能直接操作基本数据类型的数据,但对于自定义类型的数据,若未重载有关运算符,则不能用这些运算符操作自定义类型的数据。概述•运算符重载通过定义运算符重载函数实现。•运算符重载函数可以定义为类的成员或友元,若访问权限许可,也可定义为普通函数。•只能重载已定义运算符,而且当重载一个运算符时,该运算符的操作数个数、优先级和结合性保持不变。•绝大多数运算符允许重载,仅有下列五个运算符不得重载:。?:、.、*、::和sizeof•当遇到重载的运算符时,系统调用该运算符重载函数完成指定操作。重载二元运算符为类运算符•若某运算符重载函数被定义为类的成员,则称该运算符为该类的运算符,简称类运算符。•由于类运算符的第一操作数约定为当前对象(隐含),所以定义二元类运算符重载函数的一般格式为:typeClassName::operator@(Arg){…}//函数体type:函数返回值类型ClassName:运算符重载函数所在的类名operator:关键字,与其后的运算符一起构成函数名,有区别于其他函数名。@:一个重载的二元运算符Arg:函数的形参表,即第二操作数。例定义复数类,重载+运算符实现复数的加法运算。#includeiostreamusingnamespacestd;classComplex{//定义复数类floatReal,Image;//复数的实部和虚部public:Complex(floatr=0,floati=0){Real=r,Image=i;}float&AccessR(){returnReal;}float&AccessI(){returnImage;}voidShow()//显示复数,如:1-2i{coutReal;if(Image=0)cout\t+;elsecout\t;coutImagei\n;}Complexoperator+(Complex&);//重载+:复数+复数Complexoperator+(float);//重载+:复数+实数Complex&operator+=(Complex&);//重载+=:复数+=复数Complex&operator=(Complex&);//重载=:复数=复数};ComplexComplex::operator+(Complex&c){Complext;t.Real=Real//当前对象即第一操作数之实部+c.Real;//第二操作数之实部t.Image=Image+c.Image;returnt;}ComplexComplex::operator+(floats){returnComplex(Real+s,Image);}Complex&Complex::operator+=(Complex&c){Real+=c.Real;Image+=c.Image;return*this;}问1.返回值类型为Complex&为何不可?问2.返回值类型为void有何不足?•表达简洁Complex&Complex::operator=(Complex&c){Real=c.Real;Image=c.Image;return*this;}intmain(void){Complexc1(25,50),c2,c3(100,200),c4(200,400),c;c1.Show();c2=c1;c2.Show();c=c1+c3;c.Show();c+=c1;c.Show();c4+=c1+c2;c4.Show();c4=c4+200;c4.Show();return0;}问5.可否实现c4=200+c4;?若不能如何改进类Complex?由此引出友元运算符。问4.可否实现c+=20;?若不能如何改进类Complex?问3.此函数可否省略,为什么?问2.返回值类型为void有何不足?•重载的运算符与普通运算符的用法一样。•对运算符重载函数的调用由系统自动完成。•c2=c1等价于c2.operator=(c1)。问3回答•若没有为类重载赋值运算符,则编译系统自动为该类生成一个缺省的赋值运算符,以实现同类对象之间对应数据成员的逐一赋值。例:Complexc1(4,5),c2;c2=c1;c2.real=c1.real;c2.imag=c1.imag;•何时需要为类重载赋值运算符:类中含有指向动态内存的指针。•例用缺省的赋值运算符产生的问题。#includeiostream.h#includestring.hclassPerson{char*name;intage;public:Person(char*n,inta){name=newchar[strlen(n)+1];strcpy(name,n);age=a;}~Person(){delete[]name;}};namep2voidmain(){Personp1(Tom,23),p2(John,18);p2=p1;//用缺省的赋值运算符赋值}namep1堆•p2.name=p1.name;p2.age=p1.age;•存在问题:–p2对象的成员数据name所指动态内存丢失,无法释放。–p1和p2对象的成员数据name共用同一块动态内存,使两者的数据不独立,产生逻辑错误。–p1对象被撤销时,其成员数据name所指动态内存已被p2对象释放,导致一个运行错误。age=23Tom\021age=23John\0解决方法:•为该类重载赋值运算符。C++语言规定:–赋值运算符必须重载为类的成员函数;–重载的赋值运算符不能被派生类直接继承。•Person类应重载赋值运算符:Person&Person::operator=(Person&p){if(this==&p)//避免对象自我赋值return*this;delete[]name;name=newchar[strlen(p.name)+1];strcpy(name,p.name);age=p.age;return*this;}namep1堆namep2Tom\0John\0age=23age=18Tom\0namep1堆namep2Tom\0age=23age=23图.p2=p1前图.p2=p1后•重载运算符时,并不要求与所重载之运算符的意义完全相同。•例如,可将+运算符重载定义成:ComplexComplex::operator+(Complex&c){returnComplex(Real-c.Real,Image-c.Image);}即,将“+”运算符的具体操作定义成减法运算。•这并不会引起任何编译错误,但将引起逻辑上的混乱。因此,重载一个运算符时,其具体操作还应尽量与该运算符的原始含义保持一致。重载一元运算符为类运算符•由于类运算符的第一操作数约定为当前对象(隐含),所以用成员函数实现一元运算符重载的格式为:typeClassName::operator单目运算符(){…}//函数体•“++”和“--”运算符的重载方法相似,但有前置和后置之分,应在定义运算符重载函数时有所区分。•以“++”运算符的重载为例说明其实现的方法:typeClassName::operator++()//前置{…}typeClassName::operator++(int)//后置{…}•仅有形式意义,无需再写形参名。•例重载“++”运算符为类运算符。#includeiostreamusingnamespacestd;//描述空间点的三维坐标,完成三维坐标对象的“+”和“++”运算classThreeD{floatx,y,z;public:ThreeD(floata=0,floatb=0,floatc=0){x=a;y=b;z=c;}ThreeDoperator+(ThreeD&t){returnThreeD(x+t.x,y+t.y,z+t.z);}ThreeD&operator++();//前置++ThreeDoperator++(int);//后置++voidShow(){cout'('x','y','z)\n;}};ThreeD&ThreeD::operator++(){x++;y++;z++;return*this;}ThreeDThreeD::operator++(int){ThreeDt=*this;x++;y++;z++;returnt;}intmain(void){ThreeDm1(25,50,100),m2(1,2,3),m3;m1.Show();++m1;m1.Show();m2++;m2.Show();m3=++m1+m2++;m3.Show();return0;}程序运行结果:(25,50,100)(26,51,101)(2,3,4)(29,55,106)•前置“++”运算:应将加1后的对象值作为返回值,即要返回当前对象值。此时必须使用this指针。•后置“++”运算:先将当前对象加1前的值存入对象t中,再使当前对象加1,最后返回对象t的值。•注意:成员运算符重载函数不应定义为静态成员。因其运算符的左操作数为当前对象,且要使用this指针。重载运算符为友元运算符•友元运算符:某运算符重载函数被定义为类的友元。•注意:友元没有this指针,因此,参与运算的操作数都必须在运算符重载函数的参数表中明确说明。•类X的一元友元运算符的定义格式:typeoperator@(参数说明){…}•类X的二元友元运算符的定义格式:typeoperator@(参数1说明,参数2说明){…}•分别为左、右操作数,至少有一个是类X的对象。•参数为左操作数,是类X的对象或引用。++、--运算符:参数只能是类X的引用+、-运算符:参数为类X的引用或对象•例用友元运算符实现复数的运算,包括二元运算符“+”、一元运算符“-”;用成员函数实现“+=”运算。#includeiostreamusingnamespacestd;classComplex{floatReal,Image;//复数的实部和虚部public:Complex(floatr=0,floati=0){Real=r,Image=i;}float&AccessR(){returnReal;}float&AccessI(){returnImage;}voidShow(){coutReal;if(Image=0)cout\t+;elsecout\t;coutImagei\n;}//类运算符重载Complex&operator+=(Complex&);//复数+=复数//友元运算符重载friendComplexoperator+(Complex&,Complex&);//复数+复数friendComplexoperator+(Complex,float);//复数+实数friendComplexoperator+(float,Complex);//实数+复数friendComplex
本文标题:运算符重载
链接地址:https://www.777doc.com/doc-3970249 .html