资源描述
目录目录退出退出第2页 共125页运算符重载是面向对象程序设计的重要特征。运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据导致不同的行为。C+中经重载后的运算符能直接对用户自定义的数据进行操作运算,这就是C+语言中的运算符重载所提供的功能。目录目录退出退出第3页 共125页7.1 运算符重载概述7.2 运算符重载函数的两种形式7.3几个常用运算符的重载7.4 类型转换7.5 本章小结目录目录退出退出第4页 共125页7.1.1 运算符重载的好处7.1.2 运算符重载的规则目录目录退出退出第5页 共125页C+预定义的运算符只能对基本类型的数据进行操作,不能用于自定义数据类型的运算。对于用户自定义的数据类型往往需要有类似的运算操作,客观上需要定义适用用户自定义数据类型的有关运算。目录目录退出退出第6页 共125页定义一个简化的复数类complex:class complex public:double real,imag;complex(double r=0,double i=0)real=r;imag=i;目录目录退出退出第7页 共125页若要把类complex的两个对象com1和com2加在一起,下面的语句是不能实现的:void main()complex com1(1.1,2.2),com2(3.3,4.4),total;total=com1+com2;/错误错误 /目录目录退出退出第8页 共125页若要将上述类complex的两个对象相加,只要编写一个运算符函数operator+(),如下所示:complex operator+(complex om1,complex om2)complex temp;temp.real=om1.real+om2.real;temp.imag=om1.imag+om2.imag;return temp;我们就能方便地使用语句:total=com1+com2;将类complex的两个对象com1和com2相加。目录目录退出退出第9页 共125页函数功能operator+()加法operator-()减法operator*()乘法operator/()除法operator()小于.目录目录退出退出第10页 共125页运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造完成的。一般来讲,重载的功能应当与原有的功能相类似。只能重载C+预定义中已有的运算符,不可自己“创造”新的运算符进行重载。目录目录退出退出第11页 共125页以下运算符不可重载:运算符语义.成员(分量)运算符*指向成员的指针:作用域运算符?:条件运算符sizeof类型长度运算符目录目录退出退出第12页 共125页不能改变运算符的操作个数。不能改变运算符的原有优先级。不能改变运算符的原有结合特性。不能改变运算符对预定义类型数据的操作方式。重载运算符时,必须至少有一个自定义类型的数据作为操作数。目录目录退出退出第13页 共125页运算符重载是通过创建运算符重载函数来实现的,运算符重载函数定义了重载的运算符将要进行的操作。运算符重载函数一般采用以下两种形式:成员运算符函数友元运算符函数目录目录退出退出第14页 共125页7.2.1 友元运算符函数7.2.2 成员运算符函数7.2.3 成员运算符函数与友元运算符函数的比较目录目录退出退出第15页 共125页在C+中,可以把运算符重载函数定义成某个类的友元函数,称为友元运算符函数。当运算符重载为友元函数时可以自由地访问类的所有成员。运算符重载为友元函数时,运算符所需要的操作数都需要通过函数的形参来传递,在参数表中参数从左至右的顺序就是运算符操作数的顺序。目录目录退出退出第16页 共125页 友元运算符函数定义的语法形式 双目运算符重载 单目运算符重载目录目录退出退出第17页 共125页友元运算符函数的原型在类的内部声明格式如下:class X /friend 返回类型返回类型 operator运算符运算符(形参表形参表);/目录目录退出退出第18页 共125页在类外定义友元运算符函数的格式如下:返回类型返回类型 operator运算符运算符(形参表形参表)函数体函数体 目录目录退出退出第19页 共125页当用友元函数重载双目运算符时,两个操作数都要传递给运算符函数。目录目录退出退出第20页 共125页两个复数a+bi和c+di进行加、减、乘、除的方法如下:加法:(a+bi)+(c+di)=(a+c)+(b+d)i减法:(a+bi)-(c+di)=(a-c)+(b-d)i乘法:(a+bi)*(c+di)=(ac-bd)+(ad+bc)i除法:(a+bi)/(c+di)=(a+bi)*(c-di)/c2+d2目录目录退出退出第21页 共125页#include class complexpublic:complex(double r=0.0,double i=0.0);void print();friend complex operator+(complex a,complex b);friend complex operator-(complex a,complex b);friend complex operator*(complex a,complex b);friend complex operator/(complex a,complex b);private:double real;double imag;目录目录退出退出第22页 共125页complex:complex(double r,double i)real=r;imag=i;complex operator+(complex a,complex b)complex temp;temp.real=a.real+b.real;temp.imag=a.imag+b.imag;return temp;目录目录退出退出第23页 共125页complex operator-(complex a,complex b)complex temp;temp.real=a.real-b.real;temp.imag=a.imag-b.imag;return temp;目录目录退出退出第24页 共125页complex operator*(complex a,complex b)complex temp;temp.real=a.real*b.real-a.imag*b.imag;temp.imag=a.real*b.imag+a.imag*b.real;return temp;complex operator/(complex a,complex b)complex temp;double t;t=1/(b.real*b.real+b.imag*b.imag);temp.real=(a.real*b.real+a.imag*b.imag)*t;temp.imag=(b.real*a.imag-a.real*b.imag)*t;return temp;目录目录退出退出第25页 共125页void complex:print()cout0)cout+;if(imag!=0)coutimagin;void main()complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6;A3=A1+A2;A4=A1-A2;A5=A1*A2;A6=A1/A2;A1.print();A2.print();A3.print();A4.print();A5.print();A6.print();目录目录退出退出第26页 共125页主函数中的A3=A1+A2;A4=A1-A2;A5=A1*A2;A6=A1/A2;在执行时将被解释为:A3=operator+(A1,A2);A4=operator-(A1,A2);A5=operator*(A1,A2);A6=operator/(A1,A2);目录目录退出退出第27页 共125页一般而言一般而言,如果在类如果在类X中采用友元函数重载双目中采用友元函数重载双目运算符运算符,而而aa和和bb是类是类X的两个对象的两个对象,则以下两种函则以下两种函数调用方法是等价的数调用方法是等价的:aa bb;/隐式调用隐式调用 operator(aa,bb);/显式调用显式调用目录目录退出退出第28页 共125页用友元函数重载单目运算符时,需要一个显式的操作数。目录目录退出退出第29页 共125页#include class ABpublic:AB(int x=0,int y=0)a=x;b=y;friend AB operator-(AB obj);void print();private:int a,b;目录目录退出退出第30页 共125页AB operator-(AB obj)obj.a=-obj.a;obj.b=-obj.b;return obj;void AB:print()couta=a b=bendl;void main()AB ob1(50,60),ob2;ob1.print();ob2=-ob1;ob2.print();目录目录退出退出第31页 共125页#include class coordpublic:coord(int i=0,int j=0);void print();friend coord operator+(coord op);private:int x,y;coord:coord(int i,int j)x=i;y=j;目录目录退出退出第32页 共125页void coord:print()coutx:x,y:yendl;coord operator+(coord op)+op.x;+op.y;return op;void main()coord ob(10,20);ob.print();operator+(ob);ob.print();+ob;ob.print();目录目录退出退出第33页 共125页#include class coordpublic:coord(int i=0,int j=0);void print();friend coord operator+(coord&op);private:int x,y;coord:coord(int i,int j)x=i;y=j;目录目录退出退出第34页 共125页void coord:print()coutx:x,y:y用指针访问对象成员目录目录退出退出第39页 共125页在C+中,可以把运算符函数定义成某个类的成员函数,称为成员运算符函数。运算符重载为成员函数后,可以自由访问本类的任何成员。对于双目运算符,其左操作数一定是对象本身,由this指针给出,另一个操作数则需要通过运算符重载函数的参数表进行传递。对于单目运算符,对象的this指针直接给出操作数,因此不再需要任何其他参数。目录目录退出退出第40页 共125页 成员运算符函数定义的语法形式 双目运算符重载 单目运算符重载目录目录退出退出第41页 共125页成员运算符函数的原型在类的内部声明格式如下:class X /返回类型返回类型 operator运算符运算符(形参表形参表);/目录目录退出退出第42页 共125页在类外定义成员运算符函数的格式如下:返回类型返回类型 X:operator运算符运算符(形参表形参表)函数体函数体目录目录退出退出第43页 共125页在成员运算符函数的形参表中,若运算符是单目的,则参数表为空;若运算符是双目的,则参数表中有一个参数。目录目录退出退出第44页 共125页对双目运算符而言,成员运算符函数的形参表中仅有一个参数,它作为运算符的右操作数,此时当前对象作为运算符的左操作数,它是通过this指针隐含地传递给函数的。目录目录退出退出第45页 共125页#include class complexpublic:complex(double r=0.0,double i=0.0);void print();complex operator+(complex c);complex operator-(complex c);complex operator*(complex c);complex operator/(complex c);private:double real;double imag;目录目录退出退出第46页 共125页complex:complex(double r,double i)real=r;imag=i;complex complex:operator+(complex c)return complex(real+c.real,imag+c.imag);complex complex:operator-(complex c)return complex(real-c.real,imag-c.imag);目录目录退出退出第47页 共125页complex complex:operator*(complex c)return complex(real*c.real-imag*c.imag,real*c.imag+imag*c.real);complex complex:operator/(complex c)complex t1(c.real,-c.imag),t2(1/(c.real*c.real+c.imag*c.imag);return(*this)*t1*t2;void complex:print()cout0)cout+;if(imag!=0)coutimagin;目录目录退出退出第48页 共125页void main()complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6;A3=A1+A2;A4=A1-A2;A5=A1*A2;A6=A1/A2;A1.print();A2.print();A3.print();A4.print();A5.print();A6.print();目录目录退出退出第49页 共125页主函数中的A3=A1+A2;A4=A1-A2;A5=A1*A2;A6=A1/A2;在执行时将被解释为:A3=A1.operator+(A2);A4=A1.operator-(A2);A5=A1.operator*(A2);A6=A1.operator/(A2);目录目录退出退出第50页 共125页一般而言一般而言,如果在类如果在类X中采用成员函数重载双目中采用成员函数重载双目运算符运算符,成员运算符函数成员运算符函数operator 所需的一个操所需的一个操作数由对象作数由对象aa通过通过this指针隐含地传递指针隐含地传递,它的另一个它的另一个操作数操作数bb在参数表中显示在参数表中显示,aa和和bb是类是类X的两个对象的两个对象,则以下两种函数调用方法是等价的则以下两种函数调用方法是等价的:aa bb;/隐式调用隐式调用 aa.operator(bb);/显式调用显式调用 目录目录退出退出第51页 共125页对单目运算符而言,成员运算符函数的参数表中没有参数,此时当前对象作为运算符的一个操作数。目录目录退出退出第52页 共125页#include class coordpublic:coord(int i=0,int j=0);void print();coord operator+();private:int x,y;coord:coord(int i,int j)x=i;y=j;目录目录退出退出第53页 共125页void coord:print()coutx:x,y:yendl;coord coord:operator+()+x;+y;return*this;void main()coord ob(10,20);ob.print();+ob;ob.print();ob.operator+();ob.print();目录目录退出退出第54页 共125页一般而言一般而言,采用成员函数重载单目运算符时采用成员函数重载单目运算符时,以下两种方以下两种方法是等价的法是等价的:aa;/隐式调用隐式调用 aa.operator();/显式调用显式调用 成员运算符函数成员运算符函数operator 所需的一个操作数由对象所需的一个操作数由对象aa通过通过this指针隐含地传递。因此指针隐含地传递。因此,在它的参数表中没有参数。在它的参数表中没有参数。注意:关于成员函数重载单目运算符后缀方式的表示方法,注意:关于成员函数重载单目运算符后缀方式的表示方法,将在将在7.3.1节介绍。节介绍。目录目录退出退出第55页 共125页 对双目运算符而言,成员运算符函数带有一个参数,而友元运算符函数带有两个参数;对单目运算符而言,成员运算符函数不带参数,而友元运算符函数带一个参数。双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但有一种情况,必须使用友元函数。目录目录退出退出第56页 共125页例如,在类AB中,用成员运算符函数重载“+”运算符:AB:operator+(int x)AB temp;temp.a=a+x;temp.b=b+x;return temp;目录目录退出退出第57页 共125页若类AB的对象ob要做赋值运算和加法运算,以下是一条正确的语句:ob=ob+200;然而,下一条语句就不能工作了:ob=200+ob;用友元方式来重载“+”(或其他双目运算符)就能消除这种问题,从而使得内部数据类型能出现在运算符左边。目录目录退出退出第58页 共125页#include class ABpublic:AB(int x=0,int y=0);friend AB operator+(AB ob,int x);friend AB operator+(int x,AB ob);void show();private:int a,b;AB:AB(int x,int y)a=x;b=y;目录目录退出退出第59页 共125页AB operator+(AB ob,int x)return AB(ob.a+x,ob.b+x);AB operator+(int x,AB ob)return AB(x+ob.a,x+ob.b);void AB:show()couta=a b=b”只能作为成员函数。对于运算符“+=、-=、*=、/=、&=、!=、=、%=、=、=”,建议重载为成员函数。对于其他运算符,建议重载为友元函数。目录目录退出退出第63页 共120页7.3.1 单目运算符“+”和“-”的重载7.3.2 赋值运算符“=”的重载7.3.3 插入运算符“”重载目录目录退出退出第64页 共120页在C+中,可以通过在运算符函数参数表中是否插入关键字int来区分前缀和后缀这两种方式。对于前缀方式对于前缀方式+ob,可以用运算符函数重载为可以用运算符函数重载为 ob.operator+();/成员函数重载成员函数重载 或或 operator+(X&ob);/友元函数重载友元函数重载,其中其中ob为类为类X对象的引用对象的引用目录目录退出退出第65页 共120页对于后缀方式对于后缀方式ob+,可以用运算符函数重载为可以用运算符函数重载为 ob.operator+(int);/成员函数重载成员函数重载 或或 operator+(X&ob,int);/友元函数重载友元函数重载在调用后缀方式的函数时在调用后缀方式的函数时,参数参数int一般被传递给一般被传递给值值0。目录目录退出退出第66页 共120页#include class three_dpublic:three_d()x=0;y=0;z=0;three_d(int i,int j,int k)x=i;y=j;z=k;void show(int&i,int&j,int&k)i=x;j=y;k=z;three_d operator+();three_d operator+(int);friend three_d operator-(three_d&);friend three_d operator-(three_d&,int);private:int x,y,z;目录目录退出退出第67页 共120页three_d three_d:operator+()+x;+y;+z;return*this;three_d three_d:operator+(int)x+;y+;z+;return*this;three_d operator-(three_d&op)-op.x;-op.y;-op.z;return op;three_d operator-(three_d&op,int)op.x-;op.y-;op.z-;return op;目录目录退出退出第68页 共120页 void main()three_d ob1(10,10,10),ob2(20,20,20);int x,y,z;ob1.show(x,y,z);cout(ob1)x:x,y:y,z:zendl;ob1+;/operator+(int)ob1.show(x,y,z);cout(ob1+)x:x,y:y,z:zendl;+ob1;/operator+()ob1.show(x,y,z);cout(+ob1)x:x,y:y,z:zendl;cout-endl;目录目录退出退出第69页 共125页ob2.show(x,y,z);cout(ob2)x:x,y:y,z:zendl;operator-(ob2);/-ob2;ob2.show(x,y,z);cout(-ob2)x:x,y:y,z:zendl;operator-(ob2,0);/ob2-;ob2.show(x,y,z);cout(ob2-)x:x,y:y,z:zendl;目录目录退出退出第70页 共120页#include class Numberpublic:Number(int i)num=i;int operator+()num+;return num;int operator+(int)int i=num;num+;return i;void print()coutnumendl;private:int num;;;目录目录退出退出第71页 共120页void main()Number n(100);int i=+n;couti=iendl;i=n+;couti=iendl;n.print();目录目录退出退出第72页 共120页运算符“+”和“-”都对单值操作数产生影响,因此用成员运算符函数重载自增运算符“+”与自减运算符“-”的成员函数通常返回指针this。由于友元运算符函数没有this指针,所以不能引用this指针所指的对象。使用友元运算符函数重载自增运算符“+”或自减运算符“-”时,应采用引用参数传递数据。目录目录退出退出第73页 共120页前缀方式和后缀方式的函数内部的语句可以相同,也可以不同,取决于编程者的考虑。目录目录退出退出第74页 共120页对任一类X,如果没有用户自定义的赋值运算符函数,那么系统自动地为其生成一个缺省的赋值运算符函数,定义为类X中的成员到成员的赋值,例如:X&X:operator=(const X&source)/成员间赋值成员间赋值 目录目录退出退出第75页 共125页若obj1和obj2是类X的两个对象,obj2已被创建,则编译程序遇到如下语句:obj1=obj2;就调用缺省的赋值运算符函数,将对象obj2的数据成员的值逐个赋给对象obj1的对应数据成员中。目录目录退出退出第76页 共125页通常,缺省的赋值运算符函数是能够胜任工作的。但是,对于许多重要的实用类来说,仅有缺省的赋值运算符函数还是不够的,还需要用户根据实际需要自己对赋值运算符进行重载。指针悬挂问题 重载赋值运算符解决指针悬挂问题目录目录退出退出第77页 共125页在某些特殊情况下,如类中有指针类型时,使用缺省的赋值运算符函数会产生错误。请看下面的例子:目录目录退出退出第78页 共125页#include#include class string public:string(char*s)ptr=new charstrlen(s)+1;strcpy(ptr,s);string()delete ptr;void print()coutptrendl;private:char*ptr;;目录目录退出退出第79页 共125页 void main()string p1(book);string p2(pen);p1=p2;coutp2:;p2.print();coutp1:;p1.print();目录目录退出退出第80页 共125页为了解决上述使用缺省的赋值运算符所遇到的指针悬挂问题,必须重载赋值运算符,使得对目标对象数据成员指针的赋值,是把原对象指针ptr所指向的内容传递给它,而不是简单地传递指针值。目录目录退出退出第81页 共125页#include#include class string public:string(char*s)ptr=new charstrlen(s)+1;strcpy(ptr,s);string()delete ptr;void print()coutptrendl;string&operator=(const string&);/声明赋值运算符重载函数声明赋值运算符重载函数 private:char*ptr;目录目录退出退出第82页 共125页string&string:operator=(const string&s)/定义赋值运算符重载函数定义赋值运算符重载函数 if(this=&s)return*this;/防止防止s=s的赋值的赋值 delete ptr;/释放掉原区域释放掉原区域 ptr=new charstrlen(s.ptr)+1;/分配新区域分配新区域 strcpy(ptr,s.ptr);/字符串拷贝字符串拷贝 return*this;目录目录退出退出第83页 共125页void main()string p1(book);string p2(pen);p1=p2;coutp2:;p2.print();coutp1:;p1.print();目录目录退出退出第84页 共125页类的赋值运算符“=”只能重载为成员函数,而不能把它重载为友元函数。类的赋值运算符“=”可以被重载,但重载了的运算符函数operator=()不能被继承。目录目录退出退出第85页 共125页把输出与输入看作数据的流动过程,因此把输出数据与输入数据称为输出流与输入流,对其操作称为插入与提取。预定义插入符 插入运算符“”重载 目录目录退出退出第86页 共125页系统预定义有一个ostream类,用于管理数据的输出,cout就是它的一个对象。表达式 couti;将被编译器解释为cout.operator(i);其中,i是传递给这个对象并启动其方法函数operator的一个消息。称为插入运算符。目录目录退出退出第87页 共125页系统提供的重载函数operator()原型为:ostream&ostream:operator(type&obj);目录目录退出退出第88页 共125页系统预定义的type为以下类型之一:char、int、short、long或unsigned、signed类型;float、double、long double类型;char*或void*类型。目录目录退出退出第89页 共125页函数operator()是类ostream的重载方法函数,其参数分别为系统预定义的上述各type类型。这个函数返回一个ostream的引用类型,系统预定义的流cout,cerr,clog是ostream类的对象。对于下面的提取表达式 coutijk将被解释为 (cout.operator(i).operator(j).operator(k)目录目录退出退出第90页 共125页当type为char*时,用于在流中插入一个字符串;当type为void*时用于在流中插入一个指针的值(地址),编译器将按所调用的重载插入函数的参数类型与void*匹配。如下例中,分别输出字符串的值和其首地址。目录目录退出退出第91页 共125页#include void main()const char*s=Hello,Visual C+!;coutsendl;cout(void*)sendl;目录目录退出退出第92页 共125页应当注意插入表达式中的副作用。这种副作用来自于以下两个方面:程序员对语法理解的错误 编译器执行的随意性目录目录退出退出第93页 共125页如表达式couta?1:0;就是对优先级别错误理解的结果。正确的写法应是:cout(a?1:0);目录目录退出退出第94页 共125页#include int fun()coutSorry,I am first!endl;return 200;void main()coutThe value of function fun()is:fun()endl;目录目录退出退出第95页 共125页#include void main()int i=1;coutfirst:i+,second:i+endl;目录目录退出退出第96页 共125页通过重载运算符“”可以实现用户自定义类型的输出。定义输出运算符“”重载函数的一般格式如下:ostream&operator(ostream&out,class_name&obj)outobj.item1;outobj.item2;.outobj.itemn;return out;目录目录退出退出第97页 共125页函数中第一个参数是对ostream对象的引用。这意味着out必须是输出流,它可以是其他任何合法的标识符,但必须与return后面的标识符相同。第二个参数为用户自定义类型class_name的对象引用。item1,.,itemn为用户自定义类型中的各个域分量。由于类中的私有数据成员不允许类的使用者直接访问,所以重载运算符函数应该使用友元函数。目录目录退出退出第98页 共125页 插入符重载函数必须是一个友元。插入符重载函数有两个参数:第一个参数为对ostream类的引用,是插入表达式中的流,第二个参数是对自定义类型的引用。插入符重载函数必须返回对ostream类的引用,以保证可在一个插入表达式中插入多个对象。目录目录退出退出第99页 共125页#include class Fractionprivate:int fz;/分子分子int fm;/分母分母public:Fraction(int n=1,int m=1);friend Fraction operator+(Fraction&,Fraction&);friend Fraction operator*(Fraction&,Fraction&);friend ostream&operator(ostream&,Fraction&);目录目录退出退出第100页 共125页Fraction:Fraction(int n,int m)int r,n1=n,m1=m;do r=n1%m1;n1=m1;m1=r;while(r);/求分子、分母的最大公约数求分子、分母的最大公约数 fz=n/n1;fm=m/n1;/使分子、分母互质使分子、分母互质 if(fm0)fz*=-1;fm*=-1;/使分母为正数使分母为正数目录目录退出退出第101页 共125页Fraction operator+(Fraction&f1,Fraction&f2)return Fraction(f1.fz*f2.fm+f1.fm*f2.fz,f1.fm*f2.fm);Fraction operator*(Fraction&f1,Fraction&f2)return Fraction(f1.fz*f2.fz,f1.fm*f2.fm);目录目录退出退出第102页 共125页ostream&operator(ostream&out,Fraction&f)if(f.fz=0)out0;else if(f.fm=1)outf.fz;else outf.fz/f.fm;return out;目录目录退出退出第103页 共125页void main()Fraction f1(1,2),f2(1,6),f3,f4;f3=f1+f2;f4=f1*f2;coutf1=f1 f2=f2endl;coutf3=f1+f2=f3 f4=f1*f2=f4 称为提取运算符。预定义的提取符是类istream的成员函数,原型为:istream&istream:operator(type&obj);目录目录退出退出第105页 共125页其中type类型除不可为void*之外,其余与预定义的插入符相同。流的提取过程如下:对输入流对象cin的提取操作,在用户输入完数据并按下回车键之后才进行。输入的数据被放到输入缓冲区中。缓冲区中的当前指针跳过输入数据的前导空白,指向一个数据。目录目录退出退出第106页 共125页当一次输入的数据不足时,程序将等待继续输入;当输入的数据(即缓冲区中的数据)多余时,遇到下一次操作才被提取。输入流中数据的类型必须与提取变量的类型一致,否则会导致提取失败。当一个提取失败后,后面的提取操作也不会提取到相应的数据。目录目录退出退出第107页 共125页定义输入运算符函数与输出运算符函数的格式基本相同,其格式如下:istream&operator(istream&in,class_name&obj)inobj.item1;inobj.item2;.inobj.itemn;return in;目录目录退出退出第108页 共125页 提取符重载函数必须是一个友元。提取符重载函数有两个参数:第一个参数为对istream类的引用,是提取表达式中的流,第二个参数是对自定义类型的引用。提取符重载函数必须返回对istream类的引用,以保证可在一个提取表达式中提取多个对象。目录目录退出退出第109页 共125页#include class Fractionprivate:int fz;/分子分子int fm;/分母分母public:Fraction(int n=1,int m=1);Fraction operator-=(Fraction&);friend int operator(Fraction&,Fraction&);friend ostream&operator(istream&,Fraction&);目录目录退出退出第110页 共125页Fraction:Fraction(int n,int m)int r,n1=n,m1=m;do r=n1%m1;n1=m1;m1=r;while(r);/求分子、分母的最大公约数求分子、分母的最大公约数 fz=n/n1;fm=m/n1;/使分子、分母互质使分子、分母互质 if(fm(Fraction&f1,Fraction&f2)return(f1.fz*f2.fm-f1.fm*f2.fz)*f1.fm*f2.fm)0);目录目录退出退出第112页 共125页ostream&operator(ostream&out,Fraction&f)if(f.fz=0)out0;else if(f.fm=1)outf.fz;else outf.fz/(istream&in,Fraction&f)char ch;inf.fz;inch;if(ch=/)inf.fm;else cerrIllegal input format!;if(f.fm0)f.fz*=-1;f.fm*=-1;return in;目录目录退出退出第114页 共125页void main()Fraction f1,f2;coutf1f2;coutf1=f1 f2=f2endl;coutf2)=f2)endl;f1-=f2;coutafter excute f1-=f2,f1=f1endl;目录目录退出退出第115页 共125页7.4.1 系统预定义类型间的转换目录目录退出退出第116页 共125页类型转换是将一种类型的值转换为另一种类型值。对于系统预定义的类型,C+提供了两种类型转换方式:隐式类型转换(标准类型转换)显示类型转换目录目录退出退出第117页 共121页隐式类型转换主要遵循以下规则:在赋值表达式A=B的情况下,赋值运算符右端B的值需转换为A类型后进行赋值。当char或short类型变量与int类型变量进行运算时,将char或short类型转换成int 类型。当两个操作对象类型不一致时,在算术运算前,级别低的自动转换为级别高的类型。目录目录退出退出第118页 共125页显示类型转换常用下述方法表示:强制转换法格式为:(类型名)表达式例如:int i,j;cout(float)(i+j);目录目录退出退出第119页 共121页 函数法转换格式为:类型名(表达式)例如:int i,j;coutfloat(i+j);目录目录退出退出作业题作业题1.请为complex类(复数类)定义下列运算符重载函数(1)算术运算符+、-、*、/;(2)求复数的共轭运算符!(3)插入运算符 第120页 共121页目录目录退出退出2请为fraction类(分数类)定义下列运算符重载函数()算术运算符+、-、*、/;()关系运算符,=,=,!=()插入运算符作业题作业题第121页 共121页
展开阅读全文