1第十章运算符重载2函数的重载所谓函数的重载是指完成不同功能的函数可以具有相同的函数名。C++的编译器是根据函数的实参来确定应该调用哪一个函数的。intfun(inta,intb){returna+b;}intfun(inta){returna*a;}voidmain(void){coutfun(3,5)endl;coutfun(5)endl;}82531、定义的重载函数必须具有不同的参数个数,或不同的参数类型。只有这样编译系统才有可能根据不同的参数去调用不同的重载函数。2、仅返回值不同时,不能定义为重载函数。4intsum,a=3,b=2;(int)=(int)+(int)sum=a+b;floatadd,x=3.2,y=2.5;(float)=(float)+(float)add=x+y;charstr[4],c1[2]=a,c2[2]=b;(char*)=(char*)+(char*)str=c1+c2;编译系统中的运算符“+”本身不能做这种运算,若使上式可以运算,必须重新定义“+”运算符,这种重新定义的过程成为运算符的重载。系统自动识别数据类型5classA{floatx,y;public:A(floata=0,floatb=0){x=a;y=b;}}voidmain(void){Aa(2,3),b(3,4),c;c=a+b;}两对象不能使用+,必须重新定义+运算符重载就是赋予已有的运算符多重含义。C++通过重新定义运算符,使它能够用于特定类的对象执行特定的功能6运算符的重载从另一个方面体现了OOP技术的多态性,且同一运算符根据不同的运算对象可以完成不同的操作。为了重载运算符,必须定义一个函数,并告诉编译器,遇到这个重载运算符就调用该函数,由这个函数来完成该运算符应该完成的操作。这种函数称为运算符重载函数,它通常是类的成员函数或者是友元函数。运算符的操作数通常也应该是类的对象。7重载为类的成员函数格式如下:类名operator运算符(参数表){函数体}Aoperator+(A&);//重载了类A的“+”运算符其中:operator是定义运算符重载函数的关键字,它与其后的运算符一起构成函数名。返回类型运算的对象关键字函数名运算的对象8classA{inti;public:A(inta=0){i=a;}voidShow(void){couti=iendl;}voidAddA(A&a,A&b)//利用函数进行类之间的运算{i=a.i+b.i;}};voidmain(void){Aa1(10),a2(20),a3;a1.Show();a2.Show();//a3=a1+a2;//不可直接运算a3.AddA(a1,a2);//调用专门的功能函数a3.Show();}没有重载运算符的例子利用函数完成了加法运算用和作对象调用函数9classA{inti;public:A(inta=0){i=a;}voidShow(void){couti=iendl;}voidAddA(A&a,A&b)//利用函数进行类之间的运算{i=a.i+b.i;}Aoperator+(A&a)//重载运算符+{At;t.i=i+a.i;returnt;}};voidmain(void){Aa1(10),a2(20),a3;a1.Show();a2.Show();a3=a1+a2;//重新解释了加法,可以直接进行类的运算a3.AddA(a1,a2);//调用专门的功能函数a3.Show();}相当于a3=a1.operator+(a2)10重载运算符与一般函数的比较:相同:1)均为类的成员函数;2)实现同一功能voidAddA(A&a,A&b){i=a.i+b.i;}Aoperator+(A&a){At;t.i=i+a.i;returnt;}a3=a1+a2;a3.AddA(a1,a2);返回值函数名形参列表由对象a3调用函数调用:返回值函数名形参函数调用:a3=a1.operator+(a2);由对象a1调用11Aoperator+(A&a){At;t.i=i+a.i;returnt;}a3=a1+a2;返回值函数名形参函数调用:a3=a1.operator+(a2);由对象a1调用总结:重新定义运算符,由左操作符调用右操作符。最后将函数返回值赋给运算结果的对象。12classA{inti;public:A(inta=0){i=a;}voidShow(void){couti=iendl;}voidAddA(A&a,A&b)//利用函数进行类之间的运算{i=a.i+b.i;}Aoperator+(A&a)//重载运算符+{At;t.i=i+a.i;returnt;}};voidmain(void){Aa1(10),a2(20),a3;a1.Show();a2.Show();a3=a1+a2;//重新解释了加法,可以直接进行类的运算a3.AddA(a1,a2);//调用专门的功能函数a3.Show();}相当于a3=a1.operator+(a2)13当用成员函数实现运算符的重载时,运算符重载函数的参数只能有二种情况:没有参数或带有一个参数。对于只有一个操作数的运算符(如++),在重载这种运算符时,通常不能有参数;而对于有二个操作数的运算符,只能带有一个参数。这参数可以是对象,对象的引用,或其它类型的参数。在C++中不允许重载有三个操作数的运算符142、在C++中,允许重载的运算符列于表13.1中。3、在C++中不允许重载的运算符列于表13.2。4、只能对C++中已定义了的运算符进行重载,而且,当重载一个运算符时,该运算符的优先级和结合律是不能改变的。15classroom{floatLength;floatWide;public:room(floata=0.0,floatb=0.0){Length=a;Wide=b;}voidShow(void){coutLength=Length'\t'Wide=Wideendl;}voidShowArea(void){coutArea=Length*Wideendl;}roomoperator+(room&);//重载运算符+,函数原型};roomroom::operator+(room&r)//重载运算符,函数定义{roomrr;rr.Length=Length+r.Length;rr.Wide=Wide+r.Wide;returnrr;}voidmain(void){roomr1(3,2),r2(1,4),r3,r4;r1.Show();r2.Show();r3=r1+r2;r3.Show();r4=r1+r2+r3;r4.Show();}r4=r1+r2+r3;(r1+r2);(r1+r2)+r3;r4=r1+(r2+r3);(r2+r3);r1+(r2+r3);运算符的优先级和结合律是不能改变的16classA{inti;public:A(inta=0){i=a;}voidShow(void){couti=iendl;}Aoperator+(A&a)//重载运算符+{At;t.i=i+a.i;returnt;}voidoperator+=(A&a){i=i+a.i;}};voidmain(void){Aa1(10),a2(20),a3;a1.Show();a2.Show();a3=a1+a2;a1+=a2;a3.Show();}由左操作符调用右操作符,没有返回值,故函数类型为void。相当于a3=a1.operator+(a2)相当于a1.operator+=(a2)17单目运算符的重载只具有一个操作数的运算符为单目运算符,最常用的为++及--。Aa,b;b=++a;b=a++;Aa;++a;a++;可以看出,虽然运算后对象a的值一致,但先自加或后自加的重载运算符函数的返回值不一致,必须在重载时予以区分。18++为前置运算时,它的运算符重载函数的一般格式为:typeoperator++(){......;}++为后置运算时,它的运算符重载函数的一般格式为:typeoperator++(int){......;}Aa,b;b=++a;b=a++;Aoperator++(){....}Aoperator++(int){....}19classA{floatx,y;public:A(floata=0,floatb=0){x=a;y=b;}Aoperator++(){At;t.x=++x;t.y=++y;returnt;}Aoperator++(int){At;t.x=x++;t.y=y++;returnt;}};voidmain(void){Aa(2,3),b;b=++a;b=a++;}20Aoperator++(){At;t.x=++x;t.y=++y;returnt;}b=++a;b=a.operator++();返回值函数名23at3344t作为函数值返回赋给bAoperator++(){++x;++y;return*this;}将对象本身作为函数值返回赋给b21Aoperator++(int){At;t.x=x++;t.y=y++;returnt;}b=a++;b=a.operator++(3);23at3243返回值函数名t作为函数值返回赋给b22classincount{intc1,c2;public:incount(inta=0,intb=0){c1=a;c2=b;}voidShow(void){coutc1=c1'\t'c2=c2endl;}incountoperator++(){c1++;c2++;return*this;}//前置++incountoperator++(int)//后置++{incountc;c.c1=c1;c.c2=c2;c1++;c2++;returnc;}};voidmain(void){incountic1(10,20),ic2(100,200),ic3,ic4;ic1.Show();ic2.Show();ic3=++ic1;//ic3=ic1.operator++()ic4=ic2++;//ic4=ic4.operator++(3)ic3.Show();ic4.Show();}ic1.c1=11ic3.c2=21ic3.c1=11ic3.c2=21ic2.c1=20ic2.c2=200ic4.c1=100ic4.c2=200因为结果要赋值,所以函数要有返回值23用成员函数实现运算符的重载时,运算符的左操作数为当前对象,并且要用到隐含的this指针。运算符重载函数不能定义为静态的成员函数,因为静态的成员函数中没有this指针。24运算符重载为友元函数运算符重载为成员函数时,是由一个操作数调用另一个操作数。Aa,b,c;c=a+b;实际上是c=a.operator+(b);c=++a;实际上是c=a.operator++();即函数的实参只有一个或没有。c+=a;实际上是c.operator+=(a);重载+=25友元函数是在类外的普通函数,与一般函数的区别是可以调用类中的私有或保护数据。将运算符的重载函数定义为友元函数,参与运算的对象全部成为函数参数。Aa,b,c;c=a+b;实际上是c=operator+(a,b);c=++a;实际上是c=operator++(a);c+=a;实际上是operator+=(c,a);26对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。有些运算符不能重载为友元函数,它们是:=,(),[],-等格式为:friend类型说明operator运算符(参数表){......}c=a+b;//c=operator+(a,b)friendAoperator+(A&a,A&b){.....}27classA{inti;public:public:A(inta=0){i