资源描述
单击此处编辑母版标题样式,单击此处编辑母版副标题样式,第10章 运算符重载,10.1,什么是运算符重载,10.2 运算符重载的方法,10.3 重载运算符的规则,10.4 运算符重载函数作为类成员函数和友元函数,10.5 重载双目运算符,10.6 重载单目运算符,10.7 重载流插入运算符和流提取运算符,10.8 不同类型数据间的转换,所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能。,运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。,现在要讨论的问题是:用户能否根据自己的需要对,C+,已提供的运算符进行重载,赋予它们新的含义,使之一名多用。譬如,能否用“+”号进行两个复数的相加。在,C+,中不能在程序中直接用运算符“+”对复数进行相加运算。用户必须自己设法实现复数相加。例如用户可以通过定义一个专门的函数来实现复数相加。见例10.1。,10.1 什么是运算符重载,例10.1 通过函数来实现复数相加。,#,include,using namespace std;,class Complex /,定义,Complex,类,public:,Complex()real=0;,imag,=0;/,定义构造函数,Complex(double r,double i)real=r;,imag,=i;/,构造函数重载,Complex complex_add(Complex /,声明复数相加函数,void display();/,声明输出函数,private:,double real;/,实部,double,imag,;/,虚部,;,Complex Complexcomplex_add(Complex&c2),Complex c;,c.real=real+c2.real;,c.,imag,=,imag,+c2.,imag,;,return c;,void Complexdisplay()/,定义输出函数,cout,(real,imag,i),endl,;,int,main(),Complex c1(3,4),c2(5,-10),c3;/,定义3个复数对象,c3=plex_add(c2);/,调用复数相加函数,cout,c1=;c1.display();/,输出,c1,的值,cout,c2=;c2.display();/,输出,c2,的值,cout,c1+c2=;c3.display();/,输出,c3,的值,return 0;,运行结果如下:,c1=(3+4i),c2=(5-10i),c1+c2=(8,-6i),结果无疑是正确的,但调用方式不直观、太烦琐,使人感到很不方便。能否也和整数的加法运算一样,直接用加号“+”来实现复数运算呢?如,c3=c1+c2;,编译系统就会自动完成,c1,和,c2,两个复数相加的运算。如果能做到,就为对象的运算提供了很大的方便。这就需要对运算符“+”进行重载。,运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该函数,以实现相应的运算。也就是说,运算符重载是通过定义函数实现的。运算符重载实质上是函数的重载。,重载运算符的函数一般格式如下:,函数类型,operator,运算符名称(形参表列),对运算符的重载处理,例如,想将“+”用于,Complex,类(复数)的加法运算,函数的原型可以是这样的:,Complex operator+(Complex,10.2 运算符重载的方法,在定义了重载运算符的函数后,可以说:函数,operator+,重载了运算符+。,为了说明在运算符重载后,执行表达式就是调用函数的过程,可以把两个整数相加也想像为调用下面的函数:,int,operator+(,int,a,int,b),return(a+b);,如果有表达式5+8,就调用此函数,将5和8作为调用函数时的实参,函数的返回值为13。这就是用函数的方法理解运算符。,可以在例10.1程序的基础上重载运算符“+”,使之用于复数相加。,例10.2 改写例10.1,重载运算符“+”,使之能用于两个复数相加。,#,include,using namespace std;,class Complex,public:,Complex()real=0;,imag,=0;,Complex(double r,double i)real=r;,imag,=i;,Complex operator+(Complex /,声明重载运算符的函数,void display();,private:,double real;,double,imag,;,;,Complex Complexoperator+(Complex&c2)/,定义重载运算符的函数,Complex c;,c.real=real+c2.real;,c.,imag,=,imag,+c2.,imag,;,return c;,void Complexdisplay(),cout,(real,imag,i),endl,;,int,main(),Complex c1(3,4),c2(5,-10),c3;,c3=c1+c2;/,运算符+用于复数运算,cout,c1=;c1.display();,cout,c2=;c2.display();,cout,real+c2.real,this-real,就是,c1.real。,在10.2节中已说明,在将运算符函数重载为成员函数后,如果出现含该运算符的表达式,如,c1+c2,编译系统把它解释为,c1.,operator+,(c2),即通过对象,c1,调用运算符重载函数,并以表达式中第二个参数(运算符右侧的类对象,c2),作为函数实参。运算符重载函数的返回值是,Complex,类型,返回值是复数,c1,和,c2,之和(,Complex(c1.real+c2.real,c1.,imag,+c2.,imag,)。,运算符重载函数除了可以作为类的成员函数外,还可以是非成员函数。可以将例10.2改写为例10.3。,例10.3 将运算符“+”重载为适用于复数加法,重载函数不作为成员函数,而放在类外,作为,Complex,类的友元函数。,#,include,using namespace std;,class Complex,public:,Complex()real=0;,imag,=0;,Complex(double r,double i)real=r;,imag,=i;,friend Complex operator+(Complex/,重载函数作为友元函数,void display();,private:,double real;,double,imag,;,;,Complex operator+(Complex&c1,Complex&c2)/,定义作为友元函数的重载函数,return Complex(c1.real+c2.real,c1.,imag,+c2.,imag,);,void Complexdisplay(),cout,(real,imag,i),endl,;,int,main(),Complex c1(3,4),c2(5,-10),c3;,c3=c1+c2;,cout,c1=;c1.display();,cout,c2=;c2.display();,cout,”、类型转换运算符)。,由于友元的使用会破坏类的封装,因此从原则上说,要尽量将运算符函数作为成员函数。但考虑到各方面的因素,一般将单目运算符重载为成员函数,将双目运算符重载为友元函数。在学习了本章第10.7节例10.9的讨论后,读者对此会有更深入的认识。,说明:有的,C+,编译系统(如,Visual C+6.0),没有完全实现,C+,标准,它所提供不带后缀.,h,的头文件不支持把成员函数重载为友元函数。上面例10.3程序在,GCC,中能正常运行,而在,Visual C+6.0,中会编译出错。但是,Visual C+,所提供的老形式的带后缀.,h,的头文件可以支持此项功能,因此可以将程序头两行修改如下,即可顺利运行:,#,include,以后如遇到类似情况,亦可照此办理。,双目运算符(或称二元运算符)是,C+,中最常用的运算符。双目运算符有两个操作数,通常在运算符的左右两侧,如3+5,a=b,i10,等。在重载双目运算符时,不言而喻在函数中应该有两个参数。下面再举一个例子说明重载双目运算符的应用。,10.5 重载双目运算符,例10.4 定义一个字符串类,String,,用来存放不定长的字符串,重载运算符“=”,“”,用于两个字符串的等于、小于和大于的比较运算。,为了使读者便于理解程序,同时也使读者了解建立程序的步骤,下面分几步来介绍编程过程。,(1)先建立一个,String,类:,#,include,using namespace std;,class String,public:,String()p=NULL;/,默认构造函数,String(char*,str,);/,构造函数,void display();,private:,char*p;/,字符型指针,用于指向字符串,;,StringString(char*,str,)/,定义构造函数,p=,str,;/,使,p,指向实参字符串,void Stringdisplay()/,输出,p,所指向的字符串,cout,p;,int,main(),String string1(Hello),string2(Book);,string1.display();,cout,”。程序如下:,#,include,#include,using namespace std;,class String,public:,String()p=NULL;,String(char*,str,);,friend,bool,operator(String/,声明运算符函数为友元函数,void display();,private:,char*p;/,字符型指针,用于指向字符串,;,StringString(char*,str,),p=,str,;,void Stringdisplay()/,输出,p,所指向的字符串,cout,(String&string1,String&string2)/,定义运算符重载函数,if(,strcmp,(string1.p,string2.p)0),return true;,else return false;,int,main(),String string1(Hello),string2(Book);,cout,string2)(String,friend,bool,operator(String&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;,bool,operator=(String&string1,String&string2)/,对运算符“=”重载,if(,strcmp,(string1.p,string2.p)=0),return true;,else,return false;,再修改主函数:,int,main(),String string1(Hello),string2(Book),string3(Computer);,cout,string2),endl,;/,比较结果应该为,true,cout,(string1string3),endl,;/,比较结果应该为,false,cout,(string1=string2),endl,;/,比较结果应该为,false,return 0;,运行结果为,1,0,0,结果显然是对的。到此为止,主要任务基本完成。,(4)再进一步修饰完善,使输出结果更直观。下面给出最后的程序。,#,include,using namespace std;,class String,public:,String()p=NULL;,String(char*,str,);,friend,bool,operator(String,friend,bool,operator(String,friend,bool,operator=(String,void display();,private:,char*p;,;,StringString(char*,str,),p=,str,;,void Stringdisplay()/,输出,p,所指向的字符串,cout,(String&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)(string1,string2)=1),string1.display();,cout,;string2.display();,else,if(operator(string1,string2)=1),string1.display();,cout,;string2.display();,else,if(operator=(string1,string2)=1),string1.display();,cout,=;string2.display();,cout,Book,BookComputer,Hello=Hello,增加了一个,compare,函数,用来对两个字符串进行比较,并输出相应的信息。这样可以减轻主函数的负担,使主函数简明易读。,通过这个例子,不仅可以学习到有关双目运算符重载的知识,而且还可以学习怎样去编写,C+,程序。,这种方法的指导思想是:先搭框架,逐步扩充,由简到繁,最后完善。边编程,边调试,边扩充。千万不要企图在一开始时就解决所有的细节。类是可扩充的,可以一步一步地扩充它的功能。最好直接在计算机上写程序,每一步都要上机调试,调试通过了前面一步再做下一步,步步为营。这样编程和调试的效率是比较高的。读者可以试验一下。,单目运算符只有一个操作数,如!,a,-b,&c,*p,,还有最常用的+,i,和-,i,等。重载单目运算符的方法与重载双目运算符的方法是类似的。但由于单目运算符只有一个操作数,因此运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数。,下面以自增运算符“+”为例,介绍单目运算符的重载。,10.6 重载单目运算符,例10.5 有一个,Time,类,包含数据成员,minute(,分)和,sec(,秒),模拟秒表,每次走一秒,满60秒进一分钟,此时秒又从0开始算。要求输出分和秒的值。,#,include,using namespace std;,class Time,public:,Time()minute=0;sec=0;/,默认构造函数,Time(,int,m,int,s):minute(m),sec(s)/,构造函数重载,Time operator+();/,声明运算符重载函数,void display(),cout,minute:sec=60),sec-=60;/,满60秒进1分钟,+,minute;,return*this;/,返回当前对象值,int,main(),Time time1(34,0);,for(,int,i=0;i61;i+),+time1;,time1.display();,return 0;,运行情况如下:,34:1,34:2,34:59,35:0,35:1 (共输出61行),可以看到:在程序中对运算符“+”进行了重载,使它能用于,Time,类对象。“+”和“-”运算符有两种使用方式,前置自增运算符和后置自增运算符,它们的作用是不一样的,在重载时怎样区别这二者呢?,针对“+”和“-”这一特点,,C+,约定:在自增(自减)运算符重载函数中,增加一个,int,型形参,就是后置自增(自减)运算符函数。,例10.6 在例10.5程序的基础上增加对后置自增运算符的重载。修改后的程序如下:,#,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(),cout,minute:sec=60),sec-=60;,+minute;,return*this;/,返回自加后的当前对象,Time Timeoperator+(,int,)/,定义后置自增运算符“+”重载函数,Time temp(*this);,sec+;,if(sec=60),sec-=60;,+minute;,return temp;/,返回的是自加前的对象,int,main(),Time time1(34,59),time2;,cout,time1:;,time1.display();,+time1;,cout,+time1:;,time1.display();,time2=time1+;/,将自加前的对象的值赋给,time2,cout,time1+:;,time1.display();,cout,”是,C+,在类库中提供的,所有,C+,编译系统都在类库中提供输入流类,istream,和输出流类,ostream,。,cin,和,cout,分别是,istream,类和,ostream,类的对象。在类库提供的头文件中已经对“”进行了重载,使之作为流插入运算符和流提取运算符,能用来输出和输入,C+,标准类型的数据。因此,在本书前面几章中,凡是用“,cout,”,对标准类型数据进行输入输出的,都要用#,include,把头文件包含到本程序文件中。,10.7 重载流插入运算符和流提取运算符,用户自己定义的类型的数据,是不能直接用“”来输出和输入的。如果想用它们输出和输入自己声明的类型的数据,必须对它们重载。,对“”重载的函数形式如下:,istream,&operator (,istream,&,自定义类,ostream,&operator”的函数的第一个参数和函数的类型都必须是,istream,&,类型,第二个参数是要进行输入操作的类。重载“”和“”的函数作为友元函数或普通的函数,而不能将它们定义为成员函数。,在程序中,人们希望能用插入运算符“”来输出用户自己声明的类的对象的信息,这就需要重载流插入运算符“”。,例10.7 在例10.2的基础上,用重载的“”输出复数。,#,include,using namespace std;,class Complex,public:,Complex()real=0;,imag,=0;,Complex(double r,double i)real=r;,imag,=i;,Complex operator+(Complex /,运算符“+”重载为成员函数,friend,ostream,&operator (,ostream,/,运算符“”重载为友元函数,private:,10.7.1 重载流插入运算符“”,double real;,double,imag,;,;,Complex Complexoperator+(Complex&c2)/,定义运算符“+”重载函数,return Complex(real+c2.real,imag,+c2.,imag,);,ostream,&operator (,ostream,&output,Complex&c)/,定义运算符“”重载函数,output(c.real+c.,imag,i),endl,;,return output;,int,main(),Complex c1(2,4),c2(6,10),c3;,c3=c1+c2;,cout,c3;,return 0;,(,在,Visual C+6.0,环境下运行时,需将第一行改为#,include,,并删去第2行。),运行结果为,(8+14,i),可以看到在对运算符“”重载后,在程序中用“”不仅能输出标准类型数据,而且可以输出用户自己定义的类对象。用“,cout,c3”,即能以复数形式输出复数对象,c3,的值。形式直观,可读性好,易于使用。,下面对怎样实现运算符重载作一些说明。程序中重载了运算符“”,运算符重载函数中的形参,output,是,ostream,类对象的引用,形参名,output,是用户任意起的。分析,main,函数最后第二行:,cout,c3;,运算符“”的左面是,cout,前面已提到,cout,是,ostream,类对象。“”的右面是,c3,,它是,Complex,类对象。由于已将运算符“”的重载函数声明为,Complex,类的友元函数,编译系统把“,cout,c3”,解释为,operator,(,cout,c3),即以,cout,和,c3,作为实参,调用下面的,operator,函数:,ostream,&operator(,ostream,&output,Complex&c),output(c.real+c.,imag,i),endl,;,return output;,调用函数时,形参,output,成为,cout,的引用,形参,c,成为,c3,的引用。因此调用函数的过程相当于执行:,cout,(c3.real+c3.,imag,i),endl,;return,cout,;,请注意:上一行中的“”是,C+,预定义的流插入符,因为它右侧的操作数是字符串常量和,double,类型数据。执行,cout,语句输出复数形式的信息。然后执行,return,语句。请思考:,return output,的作用是什么?回答是能连续向输出流插入信息。,output,是,ostream,类的对象,它是实参,cout,的引用,也就是,cout,通过传送地址给,output,,使它们二者共享同一段存储单元,或者说,output,是,cout,的别名。因此,,return output,就是,return,cout,,,将输出流,cout,的现状返回,即保留输出流的现状。,请问返回到哪里?刚才是在执行,cout,c3;,在已知,cout,c3,的返回值是,cout,的当前值。如果有以下输出:,cout,c3c2;,先处理,cout,c3,,即,(,cout,c3)c2;,而执行(,cout,c3),得到的结果就是具有新内容的流对象,cout,,,因此,(,cout,c3)c2,相当于,cout,(,新值),c2。,运算符“”左侧是,ostream,类对象,cout,,,右侧是,Complex,类对象,c2,则再次调用运算符“”重载函数,接着向输出流插入,c2,的数据。现在可以理解了为什么,C+,规定运算符“”重载函数的第一个参数和函数的类型都必须是,ostream,类型的引用,就是为了返回,cout,的当前值以便连续输出。,请读者注意区分什么情况下的“”是标准类型数据的流插入符,什么情况下的“”是重载的流插入符。如,cout,c3,5,endl,;,有下划线的是调用重载的流插入符,后面两个“”不是重载的流插入符,因为它的右侧不是,Complex,类对象而是标准类型的数据,是用预定义的流插入符处理的。,还有一点要说明:在本程序中,在,Complex,类中定义了运算符“”重载函数为友元函数,因此只有在输出,Complex,类对象时才能使用重载的运算符,对其他类型的对象是无效的。如,cout,”的作用是从一个输入流中提取数据,如“,cin,i;”,表示从输入流中提取一个整数赋给变量,i(,假设已定义,i,为,int,型)。重载流提取运算符的目的是希望将“”用于输入自定义类型的对象的信息。,10.7.2 重载流提取运算符“”,例10.8 在例10.7的基础上,增加重载流提取运算符“”,用“,cin,”,输入复数,用“,cout,”,输出复数。,#,include,using namespace std;,class Complex,public:,friend,ostream,&operator (,ostream,/,声明重载运算符“(,istream,/,声明重载运算符“”,private:,double real;,double,imag,;,;,ostream,&operator (,ostream,&output,Complex&c)/,定义重载运算符“”,output(c.real+c.,imag,(,istream,&input,Complex&c)/,定义重载运算符“”,cout,c.realc.,imag,;,return input;,int,main(),Complex c1,c2;,cin,c1c2;,cout,c1=c1,endl,;,cout,c2=c2,endl,;,return 0;,运行情况如下:,input real part and imaginary part of complex number:,3 6,input real part and imaginary part of complex number:,4 10,c1=(3+6i),c2=(4+10i),以上运行结果无疑是正确的,但并不完善。在输入复数的虚部为正值时,输出的结果是没有问题的,但是虚部如果是负数,就不理想,请观察输出结果。,input real part and imaginary part of complex number:3 6,input real part and imaginary part of complex number:4-10,c1=(3+6i),c2=(4+-10i),根据先调试通过,最后完善的原则,可对程序作必要的修改。将重载运算符“”函数修改如下:,ostream,&operator (,ostream,&output,Complex&c),output(=0)output+;/,虚部为正数时,在虚部前加“+”号,outputc.,imag,i),endl,;/,虚部为负数时,在虚部前不加“+”号,return output;,这样,运行时输出的最后一行为,c2=(4-10i),。,通过本章前面几节的讨论,可以看到:在,C+,中,运算符重载是很重要的、很有实用意义的。它使类的设计更加丰富多彩,扩大了类的功能和使用范围,使程序易于理解,易于对对象进行操作,它体现了为用户着想、方便用户使用的思想。有了运算符重载,在声明了类之后,人们就可以像使用标准类型一样来使用自己声明的类。类的声明往往是一劳永逸的,有了好的类,用户在程序中就不必定义许多成员函数去完成某些运算和输入输出的功能,使主函数更加简单易读。好的运算符重载能体现面向对象程序设计思想。,在本章的例子中读者应当注意到,在运算符重载中使用引用(,reference),的重要性。利用引用作为函数的形参可以在调用函数的过程中不是用传递值的方式进行虚实结合,而是通过传址方式使形参成为实参的别名,因此不生成临时变量(实参的副本),减少了时间和空间的开销。此外,如果重载函数的返回值是对象的引用时,返回的不是常量,而是引用所代表的对象,它可以出现在赋值号的左侧而成为左值(,left value),,可以被赋值或参与其他操作(如保留,cout,流的当前值以便能连续使用“”输出)。但使用引用时要特别小心,因为修改了引用就等于修改了它所代表的对象。,在,C+,中,某些不同类型数据之间可以自动转换,例如,int,i=6;,i=7.5+i;,编译系统对 7.5是作为,double,型数处理的,在求解表达式时,先将6转换成,double,型,然后与7.5相加,得到和为13.5,在向整型变量,i,赋值时,将13.5转换为整数13,然后赋给,i。,这种转换是由,C+,编译系统自动完成的,用户不需干预。这种转换称为隐式类型转换。,10.8 不同类型数据间的转换,10.8.1 标准类型数据间的转换,C+,还提供显式类型转换,程序人员在程序中指定将一种指定的数据转换成另一指定的类型,其形式为,类型名(数据),如,int,(89.5),其作用是将89.5转换为整型数89。,对于用户自己声明的类型,编译系统并不知道怎样进行转换。解决这个问题的关键是让编译系统知道怎样去进行这些转换,需要定义专门的函数来处理。,转换构造函数(,conversion constructor function),的作用是将一个其他类型的数据转换成一个类的对象。,先回顾一下以前学习过的几种构造函数:,默认构造函数。以,Complex,类为例,函数原型的形式为,Complex();/,没有参数,用于初始化的构造函数。函数原型的形式为,Complex(double r,double i);/,形参表列中一般有两个以上参数,用于复制对象的复制构造函数。函数原型的形式为,10.8.2 转换构造函数,Complex(Complex /,形参是本类对象的引用,现在又要介绍一种新的构造函数转换构造函数。,转换构造函数只有一个形参,如,Complex(double r)real=r;,imag,=0;,其作用是将,double,型的参数,r,转换成,Complex,类的对象,将,r,作为复数的实部,虚部为0。用户可以根据需要定义转换构造函数,在函数体中告诉编译系统怎样去进行转换。,在类体中,可以有转换构造函数,也可以没有转换构造函数,视需要而定。以上几种构造函数可以同时出现在同一个类中,它们是构造函数的重载。编译系统会根据建立对象时给出的实参的个数与类型选择形参与之匹配的构造函数。,使用转换构造函数将一个指定的数据转换为类对象的方法如下:,(1)先声明一个类。,(2)在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法。,(3)在该类的作用域内可以用以下形式进行类型转换:,类名(指定类型的数据),就可以将指定类型的数据转换为此类的对象。,不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成转换构造函数所在的类对象。如可以将一个学生类对象转换为教师类对象,可以在,Teacher,类中写出下面的转换构造函数:,Teacher(Student,strcpy,(name,s.name);sex=s.sex;,但应注意:对象,s,中的,num,name,sex,必须是公用成员,否则不能被类外引用。,用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来将一个类的对象转换为一个其他类型的数据(例如将一个,Complex,类对象转换成,double,类型数据)。,C+,提供类型转换函数(,type conversion function),来解决这个问题。类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个,Complex,类,可以在,Complex,类中这样定义类型转换函数:,operator double(),return real;,类型转换函数的一般形式为,10.8.3 类型转换函数,operator,类型名(),实现转换的语句,在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。,从函数形式可以看到,它与运算符重载函数相似,都是用关键字,operator,开头,只是被重载的是类型名。,double,类型经过重载后,除了原有的含义外,还获得新的含义(将一个,Complex,类对象转换为,double,类型数据,并指定了转换方法)。这样,编译系统不仅能识别原有的,double,型数据,而且还会把,Complex,类对象作为,double,型数据处理。,那么程序中的,Complex,类对具有双重身份,既是,Complex,类对象,又可作为,double,类型数据。,Complex,类对象只有在需要时才进行转换,要根据表达式的上下文来决定。,转换构造函数和类型转换运算符有一个共同的功能:当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象(或临时变量)。,例10.9 使用类型转换函数的简单例子。,#,include,using namespace std;,class Complex,public:,Complex()real=0;,imag,=0;,Complex(double r,double i)real=r;,imag,=i;,operator double()return real;/,类型转换函数,private:,double real;,double,imag,;,;,int,main(),Complex c1(3,4),c2(5,-10),c3;,double d;,d=2.5+c1;/,要求将一个,double,数据与,Complex,类数据相加,cout,d,endl,;,return 0;,分析:,(1)如果在,Complex,类中没有定义类型转换函数,operator double,,程序编译将出错。,(2)如果在,main,函数中加一个语句:,c3=c2;,由于赋值号两侧都是同一类的数据,是可以合法进行赋值的,没有必要把,c2,转换为,double,型数据。,(3)如果在,Complex,类中声明了重载运算符“+”函数作为友元函数:,Complex operator+(Complex c1,Complex c2)/,定义运算符“+”重载函数,return Complex(c1.real+c2.real,c1.,imag,+c2.,imag,);,若在,main,函数中有语句,c3=c1+c2;,由于已对运算符“+”重载,使之能用于两个,Complex,类对象的相加,因此将,c1,和,c2,按,Complex,类对象处理,相加后赋值给同类对象,c3。,如果改为,d=c1+c2;/d,为,double,型变量,将,c1,与,c2,两个类对象相加,得到一个临时的,Complex,类对象,由于它不能赋值给,double,型变量,而又有对,double,的重载函数,于是调用此函数,把临时类对象转换为,double,数据,然后赋给,d。,从前面的介绍可知:对类型的重载和本章开头所介绍的对运算符的重载的概念和方法都是相似的。重载函数都使用关键字,operator,。,因此,通常把类型转换函数也称为类型转换运算符函数,由于它也是重载函数,因此也称为类型转换运算符重载函数(或称强制类型转换运算符重载函数)。,假如程序中需要对一个,Complex,类对象和一个,double,型变量进行+,-,*,/等算术运算,以及关系运算和逻辑运算,如果不用类型转换函数,就要对多种运算符进行重载,以便能进行各种运算。这样,是十分麻烦的,工作量较大,程序显得冗长。如果用类型转换函数对,double,进行重载(使,Complex,类对象转换为,double,型数据),就不必对各种运算符进行重载,因为,Complex,类对象可以被自动地转换为,double,型数据,而标准类型的数据的运算,是可以使用系统提供的各种运算符的。,例10.10 包含转换构造函数、运算符重载函数和类型转换函数的程序。,先阅读以下程序,在这个程序中只包含转换构造函数和运算符重载函数。,#,include,using namespace
展开阅读全文