版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章对运算符进行重载4.1为什么要对运算符重载4.2对运算符重载的方法4.3重载运算符的规则4.4运算符重载函数作为类成员函数和友元函数4.5重载单目运算符4.6重载流插入运算符和流提取运算符4.6.1重载流插入运算符"<<"4.6.2重载流提取运算符">>"4.7有关运算符重载的归纳4.8不同类型数据间的转换4.8.1标准类型数据间的转换4.8.2用转换构造函数进行不同类型数据的转换4.8.3类型转换函数4.1为什么要对运算符重载前面提过一般函数和构造函数可以重载。类成员函数也可以重载,规则和构造函数一样。重载函数之间靠所包含的参数的类型与个数之不同进行区分。在C++中,说明一个类就是说明一个新类型。因此,类对象和变量一样,可以作为参数传递,也可以作为返回类型。用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。例如,能否用"+"号进行两个复数的相加。重载运算符增强了C++语言的可扩充性。在基本数据类型上,系统提供了许多预定义的运算符,它们可以用一种简洁的方式工作,例如“+”运算符:
intx,y;y=x+y;这是表达两个整数相加的方法,非常简单。4.1为什么要对运算符重载若有一个类:classx{ public: inty;//…};main(){xa,b;a.y=a.y+b.y;//…return1;}4.1为什么要对运算符重载从上面的例子看出:上述表达式a.y=a.y+b.y不如y=x+y简洁,也不直观;而且还存在一个问题,若类x中的y为私有成员,上述表达式a.y=a.y+b.y就是错误的。为了表达上的方便,希望已预定义的运算符也可以在特定类的对象上以新的含义进行解释。如上面的a=a+b,这就需要重载运算符来解决。4.2运算符重载的方法运算符重载实质上是函数重载。重载运算符的一般格式如下:函数类型operator运算符名称(形参表){对运算符的重载处理}例如,想将"+"用于Complex类的加法运算,函数的原型可以是这样的:Complexoperator+(Complex&c1,Complex&c2);operator是关键字,用于定义重载运算符的函数,运算符名称就是C++已有的运算符。函数名是由operator和运算符组成的。上面的"operator+"就是函数名意思是“对运算符+重载的函数”,即函数“operator+”重载了运算符"+"。这类函数和其他函数在形式上没有什么区别。4.2运算符重载的方法例:对运算符"+"实行重载,使之能用于两个复数相加#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexoperator+(Complex&c2);voiddisplay();private:doublereal;doubleimag;};4.2运算符重载的方法ComplexComplex::operator+(Complex&c2){Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidComplex::display(){cout<<"("<<real<<","<<imag<<"i)"<<endl;}4.2运算符重载的方法intmain(){Complexc1(3,4),c2(5,-10),c3;c3=c1+c2;cout<<"c1=";c1.display();cout<<"c2=";c2.display();cout<<"c1+c2=";c3.display();return0;}4.2运算符重载的方法在将运算符“+”重载为类的成员函数后,C++编译系统将程序中的表达式c1+c2解释为c1.operator+(c2)。C++提供的运算符原来只能用于标准类型数据的运算,但C++程序设计的重要基础是类和对象,为了使类和对象有更强的生命力,C++采取的方法不是为类对象另外定义一批新的运算符,而是允许重载现有的运算符,使这些简单众所周知的运算符能直接应用于自己定义的类对象。通过运算符重载,扩大了C++已有运算符的作用范围,使之能用于类对象。4.3重载运算符的规则(1)C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。(2)C++允许重载的运算符双目算术运算符+-*/%关系运算符==!=<><=>=逻辑运算符||&&!单目运算符+-*(指针)&(取地址)自增自减运算符++--位运算符^&|
~<<>>
赋值运算符=+=-=*=
/=%=^=&=|=>>=<<=空间申请与释放newdeletenew[]delete[]其他运算符()(函数调用)->(成员访问)->*(成员指针访问),(逗号)[](下标)4.3重载运算符的规则不能被重载的运算符:.(成员访问)
::(域运算符)*(成员指针访问运算符)
?:(条件运算符)
sizeof(3)重载不能改变这些运算符所需操作数的数目。(4)重载运算符时,不能改变它们的优先级(5)重载不能改变运算符的结合性(6)重载运算符的函数不能有默认的参数,否则就改变了运算符参数的个数,与前面矛盾4.3重载运算符的规则(7)重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少有一个是类对象(或类对象的引用)。也就是说,参数不能全部是C++的标准类型,以防止用户修改标准类型数据的运算符性质。(8)用于类对象的运算符一般必须存在,但有两个例外,运算符“=”和“&”不必用户重载。“=”可以用于每一个类对象,可以利用它在同类对象之间相互赋值。“&”能返回类对象在内存中的起始地址。(9)从理论上说,可以将一个运算符重载为执行任意的操作。应该使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能。4.4运算符重载函数作为类成员函数和友元函数对运算符重载的函数有两种处理方式:(1)把运算符重载的函数作为类的成员函数(2)运算符重载的函数不是类的成员函数(可以是一个普通函数),在类中把它声明为友元函数。一、用成员函数重载运算符在C++中,运算符重载实际上是一种函数调用的形式,用成员函数重载运算符就是将运算符重载定义成一个类的成员函数的形式。
1.用成员函数重载运算符的语法形式(1)在类定义体中声明运算符函数
typeoperator@(参数表)
其中type为返回类型;operator为关键字;@为要重载的运算符符号; 若运算符为一元的,参数表为空,此当前对象作为运算符的左操作数; 若运算符是二元的,参数表中有一个操作数,此时当前对象作为运算符 的左操作数,参数表中的操作数作为此运算符的右操作数。4.4运算符重载函数作为类成员函数和友元函数前面的例子,"+"是双目运算符,为什么重载函数中只有一个参数呢?实际上,运算符重载函数应当有两个参数,由于重载函数是Complex类中的成员函数,因此有一个参数是隐含的,运算符函数是用this指针隐式地访问类对象的成员。例:
classx{ intoperator+(xa);
};(2)定义运算符函数typex::operator@(参数表){....}其中x是重载此运算符的类名,符号含义与上面相同。上面在x类中重载“+”的例子也可定义为下面的形式:intx::operator+(xa){//…}4.4运算符重载函数作为类成员函数和友元函数(3)重载运算符的使用定义后的重载运算符使用起来就像原运算符一样方便。但要注意它的操作数。一定要是定义它的特定类的对象,如上面重载“+”运算符的例子可用一个main()来使用它。main(){ xa1,b1; ya2,b2; a1=a1+b1;//正确
a2=a2+b2;//错误
//…}从例子中看出,a1=a1+b1;是正确的,因为a1,b1是类x的对象,在类x中已经重载了“+”运算符,因此可以直接使用。而a2=a2+b2;是错误,因为a2,b2是类y的对象,在y中没有定义“+”重载,因此不能使用。在类x中对“+”运算符有了重载定义,因此对此类对象进行相加时就像做一般的加法一样简单。4.4运算符重载函数作为类成员函数和友元函数
2.用成员函数重载运算符的使用举例前面讨论的point类中有两个数据成员x,y,若希望使两个点之间进行相加或相减,实际上是两个点坐标的x,y值各自相加或相减。如果使用重载运算符“+”,“-”的方法,可以使表达式之间的相加或者相减非常方便,下面给出这个例子实现的程序。4.4运算符重载函数作为类成员函数和友元函数#include<iostream.h>classpoint{ intx,y; public: point(intvx,intvy) {x=vx;y=vy;} point(){x=0;y=0;} pointoperator+(pointp1);//重载运算符"+" pointoperator-(pointp1);//重载运算符"-" voidprint() {cout<<x<<""<<y<<"\n";}};4.4运算符重载函数作为类成员函数和友元函数pointpoint::operator+(pointp1){//定义两个对象的"+"函数
pointp; p.x=x+p1.x; p.y=y+p1.y; returnp;//返回当前对象与p对象之和}pointpoint::operator-(pointp1){//定义两个对象的"+"函数
pointp; p.x=x-p1.x; p.y=y-p1.y; returnp;//返回当前对象与p对象之差}4.4运算符重载函数作为类成员函数和友元函数main(){ pointp1(10,10),p2(20,20); p1=p1+p2; p1.print(); return1;}4.4运算符重载函数作为类成员函数和友元函数二、用友元重载运算符在C++中,还可以把重载运算符定义成某个类的友元函数的形式,而且这种方法用得更多。在定义格式上与用成员函数定义相似,但稍有差别。
1.用友元重载运算符的语法形式用友元重载运算符的函数也称运算符函数。它与用成员函数重载运算符的函数之不同,在于后者本身是类中的成员函数;而它是类的友元函数,是独立于类外的一般函数。(1)在类定义体中声明重载运算符,在定义体中,要声明用友元重载的运算符时与一般的友元函数有些相似,可采用如下形式:
friendtypeoperator@(参数表);与用成员函数定义的方法相比,只是在前面多了一个friend,其他项目含义相同。4.4运算符重载函数作为类成员函数和友元函数
在为友元函数重载运算符的参数表填写操作数时,要注意友元函数是不属于任何类的,他没有this指针,这与成员函数不同。若重载的是一元运算符,则在参数表中有一个操作数;若重载的是二元运算符,则在参数表中有两个操作数,即所有的操作数均需用参数传递。 例:
classpoint{ intx,y; public://…friendpointoperator+(pointp1,pointp2);};4.4运算符重载函数作为类成员函数和友元函数(2)定义重载运算符定义用友元重载的运算符与定义一般的友元函数相似,格式如下:typeoperator@(参数表){//定义的操作}
因为此函数不属于任何类,所以不需缀上类名例如上面point类中用友元重载的”+”运算符的定义为:pointoperator+(pointp1,pointp2){ pointp; p.x=p1.x+p2.x; p.y=p1.y+p2.y; returnp;}
(3)重载运算符的使用 和用成员函数定义的重载运算符的使用一样。4.4运算符重载函数作为类成员函数和友元函数2.用友元重载运算符的使用举例例1用重载运算符的方法进行复数运算加法:(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))/(c*c+d*d)现在定义一个复数类complex。在complex类中包含两个数据成员,即复数的实数部分real和复数的虚数部分imag。在类中定义必须的成员函数,再将上述+,-,*,/四种算法用友元来重载运算符。4.4运算符重载函数作为类成员函数和友元函数#include<iostream.h>classcomplex{ floatreal,imag; public: complex(floatr,floati) {real=r;
imag=i;} complex()
{real=0;
imag=0; }voidprint(); friendcomplexoperator+(complexa,complexb); friendcomplexoperator-(complexa,complexb); friendcomplexoperator*(complexa,complexb); friendcomplexoperator/(complexa,complexb);};4.4运算符重载函数作为类成员函数和友元函数
voidcomplex::print(){ cout<<real; if(imag>0)cout<<"+"; if(imag!=0)cout<<imag<<"i\n";}complexoperator+(complexa,complexb)//重载+定义
{ complextemp; temp.real=a.real+b.real; temp.imag=a.imag+b.imag; returntemp;}
4.4运算符重载函数作为类成员函数和友元函数
complexoperator-(complexa,complexb)//重载-定义
{ complextemp; temp.real=a.real-b.real; temp.imag=a.imag-b.imag; returntemp;}complexoperator*(complexa,complexb)//重载*定义
{ complextemp; temp.real=a.real*b.real-a.imag*b.imag; temp.imag=a.real*b.imag+a.imag*b.real; returntemp;}4.4运算符重载函数作为类成员函数和友元函数
complexoperator/(complexa,complexb)//重载/定义
{ complextemp; floattt; tt=1/(b.real*b.real+b.imag*b.imag); temp.real=(a.real*b.real+a.imag*b.imag)*tt; temp.imag=(b.real*a.imag-a.real*b.imag)*tt; returntemp;}4.4运算符重载函数作为类成员函数和友元函数main(){
complexc1(2.3,4.6),c2(3.6,2.8),c3; c1.print(); c2.print(); c3=c1+c2; c3.print(); c3=c2-c1; c3.print(); c3=c1*c2; c3.print(); c3=c1/c2; c3.print(); return1;}
4.4运算符重载函数作为类成员函数和友元函数究竟把运算符重载函数作为类的成员函数好,还是友元函数好?由于友元的使用会破坏类的封装,因此从原则上说,要尽量将运算符函数作为成员函数。但考虑到各方面的因素和程序员的习惯,以下可供参考:(1)C++规定,赋值运算符=、下标运算符[]、函数调用运算符()、成员运算符->必须作为成员函数。(2)流插入<<和流提取运算符>>、类型转换运算符不能定义为类的成员函数,只能作为友元函数。(3)一般将单目运算符和复合运算符(+=,-=,、=,*=,&=,!=,……=,%=,>>=,<<=)重载为成员函数。(4)一般将双目运算符重载为友元函数。4.5重载单目运算符单目运算符的重载方法和双目运算符类似,但函数只有一个参数,如果作为成员函数,还可省略此参数。下面以自增运算符"++"为例,介绍单目运算符的重载。例:有一个Time类,包含数据成员minute(分)和sec(秒),模拟秒表,每次走一秒,满60秒进一分钟,此时秒又从0算起。要求输出分和秒的值。#include<iostream>usingnamespacestd;classTime{public:4.5重载单目运算符Time(){minute=0;sec=0;}Time(intm,ints):minute(m),sec(s){}Timeoperator++();//声明运算符重载成员函数voiddisplay(){cout<<minute<<":"<<sec<<endl;}private:intminute;intsec;};4.5重载单目运算符TimeTime::operator++(){if(++sec>=60){sec-=60;//满60秒进1分钟++minute;}return*this;//返回当前对象值}intmain(){Timetime1(34,0);for(inti=0;i<61;i++){++time1;time1.display();}return0;}4.5重载单目运算符++和--的重载假若要对类中的变量进行加1和减1操作,操作时要指明类名及变量名,若此变量名是私有成员,这种操作对类以外的对象禁止。因此,要想通过对类对象的加1或减1操作而引起其变量的相应操作,就必须对++和--进行重载。例,有一个计数器类,要对它定义两个重载运算符++,--,可以写成下面的形式:#include<iostream.h>classcounter{ unsignedintvalue; public: counter(){value=0;} voidoperator++(); voidoperator--(); intget(){returnvalue;}};4.5重载单目运算符voidcounter::operator++(){if(value<65535)value++;}voidcounter::operator--(){if(value>0)value--;}main(){ counterc1; for(inti=0;i<10;i++) c1++; cout<<c1.get()<<"\n"; c1--; c1--; cout<<c1.get()<<"\n"; return1;}4.5重载单目运算符运算符[]和()的重载运算符[]是下标运算符,运算符()是函数调用运算符,这两个运算符在重载定义时,不能用友元函数重载,只能采用成员函数重载。下面的例子是用来处理矩阵的,假如有一个实数矩阵,需要对它进行加法、减法和乘法运算,并且重载运算符(),用来返回矩阵元素的值。4.5重载单目运算符
#include<iostream.h>classmatrix{ shortrows,cols; double*elems; public: matrix(shortrows,shortcols); ~matrix();doubleoperator()(shortrow,shortcol);//重载运算符“()”,用来返回元素值 voidsetelem(shortrow,shortcol,doubleval);//为矩阵元素赋值 friendmatrixoperator+(matrixp,matrixq);//实现矩阵相加friendmatrixoperator-(matrixp,matrixq);//实现矩阵相减voidprint();//输出矩阵中各元素};4.5重载单目运算符matrix::matrix(shortrows,shortcols){ matrix::rows=rows; matrix::cols=cols; elems=newdouble[rows*cols];//为矩阵动态分配内存}inlinematrix::~matrix(){deleteelems;//释放矩阵所占内存}4.5重载单目运算符doublematrix::operator()(shortrow,shortcol){ return(row>=1&&row<=rows&&col>=1&&col<=cols)?elems[(row-1)*cols+(col-1)]:0.0;}//elems中所存放的矩阵元素是按行顺序存放,若给出矩阵下标还需进行换算后,再去elems中寻找,所以重载“()”使给出行、列值就能得到元素值,因为elems为数组,所以定义时不能重载“[]”,只能重载“()”,否则会产生二义性。voidmatrix::setelem(shortrow,shortcol,doubleval){if(row>=1&&row<=rows&&col>=1&&col<=cols)elems[(row-1)*cols+(col-1)]=val;}4.5重载单目运算符matrixoperator+(matrixp,matrixq){ matrixm(p.rows,p.cols); if(p.rows!=q.rows||p.cols!=q.cols) returnm; for(intr=1;r<=p.rows;r++) for(intc=1;c<=p.cols;c++) m.setelem(r,c,p(r,c)+q(r,c)); returnm;}4.5重载单目运算符matrixoperator-(matrixp,matrixq){ matrixm(p.rows,p.cols); if(p.rows!=q.rows||p.cols!=q.cols) returnm; for(intr=1;r<=p.rows;r++) for(intc=1;c<=p.cols;c++) m.setelem(r,c,p(r,c)-q(r,c)); returnm;}4.5重载单目运算符voidmatrix::print(){ for(intr=1;r<=this->rows;++r) { for(intc=1;c<=this->cols;c++) cout<<(*this)(r,c)<<""; cout<<"\n"; }}4.5重载单目运算符main(){ matrixa(2,3),b(2,3),d(2,3); a.setelem(1,1,1.0); a.setelem(1,2,3.0); a.setelem(1,3,3.0); a.setelem(2,1,4.0); a.setelem(2,2,5.0); a.setelem(2,3,6.0);b.setelem(1,1,1.0);b.setelem(1,2,2.0);b.setelem(1,3,3.0);b.setelem(2,1,4.0);b.setelem(2,2,5.0);b.setelem(2,3,6.0);4.5重载单目运算符a.print; b.print; d=a+b; d.print(); d=a-b; d.print();}4.6重载流插入运算符和流提取运算符cout<<和cin>>能对标准类型数据进行输入输出,用户自己定义的类型不行,需要重载。对"<<"和">>"重载的函数形式如下:istream&operator>>(istream&,自定义类&);ostream&operator<<(ostream&,自定义类&);重载运算符">>"的函数的第一个参数和函数的类型都必须是istream&类型(即istream类对象的引用),第2个参数是要进行输入操作的类。重载"<<"的函数的第一个参数和函数的类型都必须是ostream&类型,函数第2个参数是要进行输入输出操作的类。因此,只能将重载">>"和"<<"的函数作为友元函数,而不能将它们定义为成员函数。4.6.1重载流插入运算符“<<”例在例4.2的基础上,用重载的运算符"<<"输出复数。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexoperator+(Complex&c2);friendostream&operator<<(ostream&,Complex&);private:doublereal;doubleimag;};4.6.1重载流插入运算符“<<”ComplexComplex::operator+(Complex&c2){returnComplex(real+c2.real,imag+c2.imag);}ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real<<","<<c.imag<<"i)"<<endl;returnoutpt;}intmain(){Complexc1(2,4),c2(6,10),c3;c3=c1+c2;cout<<c3;return0;}4.6.1重载流插入运算符“<<”分析:cout<<c3;运算符"<<"的左面cout是头文件iostream中声明的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;returnoutput;}4.6.1重载流插入运算符“<<”调用函数的过程相当于执行:cout<<"("<<c3.real<<"+"<<c3.imag<<"i)"<<endl;returncout;returnoutput的作用是能连续向输出流插入信息。returnoutput就是returncout,将输出流cout的现状返回,即保留输出流的现状。即执行cout<<c3返回值是cout的当前值。如果有以下输出cout<<c3<<c2;先处理cout<<c3,即(cout<<c3)<<c2;而执行(cout<<c3)得到的结果是具有新内容的cout,因此,(cout<<c3)<<c2相当于cout(新值)<<c2。4.6.1重载流插入运算符“<<”运算符"<<"左侧是ostream类对象cout,右侧是Complex对象c2,再次调用运算符"<<"重载函数,接着向输出流插入c2的数据。现在可以理解了为什么C++规定运算符"<<"重载函数的第一个参数和函数的类型都必须是ostream类型的引用,就是为了返回cout的当前值以便连续输出。注意区分"<<"是重载的还是标准的。如cout<<c3<<5<<endl;4.6.2重载流提取运算符“>>”重载流提取运算符的目的是希望将">>"用于输入自定义类型的对象的信息。在例4.7的基础上,增加重载流提取运算符">>",用"cin>>"输入复数,用"cout<<"输出复数。#include<iostream>usingnamespacestd;classComplex{public:friendostream&operator<<(ostream&,Complex&);friendistream&operator>>(istream&,Complex&);private:doublereal;doubleimag;};4.6.2重载流提取运算符“>>”ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real<<","<<c.imag<<"i)"<<endl;returnoutpt;}istream&operator>>(istream&input,Complex&c){cout<<"inputrealpartandimaginarypartofcomplexnumber:";input>>c.real>>c.image;returninput;}intmain(){Complexc1,c2;cin>>c1>>c2;cout<<"c1="<<c1<<endl;cout<<"c2="<<c2<<endl;return0;}4.6.2重载流提取运算符“>>”分析:运算符">>"重载函数中的形参input是istream类的对象的引用,在执行cin>>c1时,调用"operator>>"函数,将cin地址传给input,input是cin的引用,同样c是c1的引用。因此,"input>>c.real>>c.image;"相当于"cin>>c1.real>>c1.image;"。函数返回cin的新值。用cin和">>"可以连续从输入流提取数据给程序中的Complex类对象,或者说,用cin和">>"可以连续向程序输入Complex类对象的值。cin>>c1>>c2;,每遇到一次">>"就调用一次重载运算符">>"的函数。4.7有关运算符重载的归纳(1)有了运算符重载,在声明了类之后,人们就可把用于标准类型的运算符用于自己声明的类。(2)使用运算符重载的具体做法是:I.先确定要重载的是哪一个运算符,想把它用于哪一个类,重载运算符只能把一个运算符用于一个类。II.设计运算符重载函数和有关的类。III.一般是有人编好一批运算符重载函数,集中放在一个头文件,放在指定的目录中,提供给有关的人使用。IV.使用者需要了解该头文件有哪些运算符重载,适用于什么类,函数原型。V.没有现成的重载运算符可用,自己设计。(3)注意在运算符重载中使用引用的重要性。(4)C++大多数运算符都可以重载。4.8不同类型数据间的转换类型转换就是将一种类型转换为另一种类型的值。在C++中,类被看作是用户自定义的抽象数据类型,可像一般的类型那样进行类型转换。类型转换有两种形式,一种是标准类型转换,它是隐式类型转换。另一种是显式类型转换,它包括强制法和函数法两种。4.8.1标准类型数据间的转换一般数据类型间的转换
1.标准类型转换因为它是隐式的,在书写时没有什么痕迹,要记住它的转换规则: (1)当char或short类型对象与int类型对象进行运算时,将char
或short转换为int类型。 (2)当两个操作数对象类型不一致时,在算术运算前,级别底的自动转换为级别高的类型。 (3)在赋值表达式E1=E2的情况下,赋值运算符右端的结果值需转换为E1类型后进行赋值。4.8.1标准类型数据间的转换2.显式类型转换(1)强制转换法
(类型名)表达式例如:
inti,j;cout<<(float)(i+j);(2)函数法类型名(表达式)
例如:
inti,j;cout<<float(i+j);此时i+j作为float的参数
4.8.1标准类型数据间的转换以前我们接触的是标准类型之间的转换,现在用户自己定义了类,一个自定义类的对象能否转换成标准类型?一个类的对象能否转换成另外一个类的对象?对于标准类型的转换,编译系统知道怎样进行。而对于用户自己声明的类型,编译系统不知道怎样进行转换,需要定义专门的函数来处理。4.8.2转换构造函数转换构造函数的作用是将一个其他类型的数据转换成一个类的对象。先回顾一下以前学习过的构造函数:I.默认构造函数:Complex();II.用于初始化的构造函数:Complex(doubler,doublei);III.用于复制对象的复制构造函数。Complex(Complex&c);转换构造函数只有一个参数,如:Complex(doubler){real=r;imag=0;}其作用是将double型的参数r转换成Complex类的对象,将r作为复数的实部,虚部为转换构造函数在类体中,以上几种构造函数可以同时出现在同一个类中,它们是构造函数的重载,编译系统会根据建立对象时给出的实参的个数与类型选择形参与之匹配的构造函数。假如在Complex类中定义了上面的转换构造函数,在Complex类的作用域中有以下定义:Complexc1(3.5);//建立对象c1,调用转换构造函数如果已对运算符"+"进行了重载,使之能进行两个Complex类对象的相加,若在程序中有以下表达式:c=c1+2.5;编译出错,因为不能用运算符"+"将一个Complex类对象和一个浮点数相加。可以先将2.5转换为Complex类无名对象,然后相加c=c1+Complex(2.5);//合法4.8.2转换构造函数对比Complex(2.5)和int(2.5)。int(2.5)是强制类型转换,将2.5转换为整数,Complex(2.5)也是强制类型转换,将2.5转换为Complex对象。转换构造函数只能有一个参数。如果有多个参数,就不是转换构造函数。归纳起来,使用转换构造函数将一个指定的数据转换为类对象的方法如下:(1)先声明一个类(2)在这个类中定义一个只有一个参数的构造函数,参数的类型是需要转换的类型,在函数体中指定转换的方法。(3)在该类的作用域内可以用以下形式进行类型转换:类名(指定类型的数据)就可以将指定类型的数据转换为此类的对象。4.8.2转换构造函数不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成转换构造函数所在的类对象。例如可以将一个学生类对象转换为教师类对象,要求把某学生的编号、姓名、性别复制到一个教师类对象中,可以在Teacher类中写成下面的转换构造函数:Teacher(Student&s){num=s.num;strcpy(name,);sex=s.sex;}注意:对象s中的num,name,sex必须是公用成员,否则不能被类外引用。4.8.3类型转换函数类型转换函数的作用是将一个类的对象转换成另一类型的数据。如果已声明了一个Complex类,可以在Complex类中这样定义类型转换函数:operatordouble(){returnreal;}函数返回double型变量的real的值。它的作用是将一个Complex类对象转换为一个double型数据,其值是Complex类中的数据成员real的值。注意:函数名是operatordouble。这点和运算符重载时的规律一致的。4.8.3类型转换函数类型转换函数的一般形式为operator类型名(){实现转换的语句}在函数名前面不能指定函数类型,函数没有参数。其返回值的类型是由函数名中指定的类型名来确定的(如operatordouble,返回值的类型是double)。类型转换函数只能作为成员函数,因为转换的主体是本类的对象。不能作为友元函数或普通函数。4.8.3类型转换函数从函数形式可以看到,它与运算符重载函数相似,都是用operator开头,只是被重载的是类型名。double类型经过重载后,除了原有的含义外,还获得新的含义(将一个Complex类对象转换为double类型数据,并指定了转换方法)。程序中的Complex对象既是Complex类对象,又可作为double类型数据,根据上下文来决定。转换构造函数和类型转换运算符有一个共同的功能:当需要的时候,编译系统会自动调用这些函数,建立一个无名的临时对象。例如,若已经定义d1,d2为double型变量,c1,c2为Complex类对象,如类中已定义了类型转换函数,若在程序中有以下表达式:d1=d2+c14.8.3类型转换函数编译系统发现"+"的左侧d2是double型,而c1是Complex类对象,如果没有对运算符"+"进行重载,就会检查有无类型转换函数,发现有对double的重载函数,就调用该函数,把Complex类对象c1转换为double型数据。如果类中已定义了转换构造函数并且又重载了运算符"+"(作为Complex类的友元函数),但未对double定义类型转换函数(或者说未对double重载),若有以下表达式c2=c1+d2编译系统发现运算符"+"左侧c1是Complex类对象,右侧d2是double型。寻找有无对"+"的重载,发现有operator+函数,但它是Complex类的友元函数,要求两个Complex类的形参,而d2是double,类中没有对double进行重载,因此不能把c1转换为double。4.8.3类型转换函数编译系统就去找有无转换构造函数,发现有,就调用转换构造函数Complex(d2),建立一个临时的Complex类对象,再调用operator+函数,将两个复数相加,相当于c2=c1+Complex(d2);例:将一个double数据与Complex类数据相加。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}operatordouble(){returnreal;}private:doublereal,imag;};4.8.3类型转换函数intmain(){Complexc1(3,4),c2(5,-10),c3;doubled;d=2.5+c1;//要求将一个double数据与Complex类数据相加cout<<d<<endl;return0;}程序分析:(1)如果在Complex类中没有定义转换函数operatordouble,程序编译将出错。因为不能实现double型数据与Complex类对象的相加。4.8.3类型转换函数(2)如果在main函数中加一个语句:c3=c2;由于赋值号两边都是同一类的数据,可以合法赋值,没有必要转换(3)如果在Complex类声明了重载运算符"+"函数作为友元函数:Complexoperator+(Complexc1,Complexc2)//定义运算符"+"重载函数{returnComplex(c1.real+c2.real,c1.imag+c2.imag);}若在main函数中有语句:c3=c1+c2;则将c1和c2按Complex类对象处理,相加后赋值给c类型转换函数如果改为d=c1+c2;将c1与c2两个类对象相加,得到一个Complex类对象,再转换为double数据,然后赋给d。用类型转换的好处是:假如程序中需要对一个Complex类对象和一个double型变量进行"+","-","*","/"以及关系和逻辑运算,如果不用类型转换函数,就要对多种运算符进行重载,以便能进行各种运算,比较麻烦。如果用类型转换对double进行重载,就不必对各种运算符进行重载,因为Complex类对象可以被自动地转换为double型数据。4.8.3类型转换函数例:包含转换构造函数、运算符重载函数。#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}//默认构造函数,无形参Complex(doubler){real=r,imag=0;}//转换构造函数,一个形参Complex(doubler,doublei){real=r;imag=i;}friendComplexoperator+(Complexc1,Complexc2);//重载运算符"+"的友元函数voiddisplay();private:doublereal,imag;};4.8.3类
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年国际精密仪器销售合同主要合同细节版
- 2024个人入股分红合作协议
- 二零二四年度城市智能照明系统开发合同2篇
- 2024全新版财务岗位担保协议电子版版
- 江南大学《电路与电子技术》2022-2023学年第一学期期末试卷
- 佳木斯大学《药物色谱分析实验》2021-2022学年第一学期期末试卷
- 2024saas定制化项目销售劳务合同
- 2024商铺招商商铺租赁合同范本
- 2024办学场地租赁合同协议书
- 2024年国际物业管理合同
- 中国联通宽带业务入户装维操作和服务基础规范
- 饲料行业法律法规体系课件
- 南京力学小学苏教版六年级上册数学《打折问题》课件PPT(公开课)
- 五年级上册数学课件-8.1 用字母表示数丨苏教版 (共12张PPT)
- 双绞线链路测试报告
- 少先队主题班会工作汇报模板009号课件
- 现场签证工程量确认单
- 人教版七年级数学上册 《实际问题与一元一次方程》教学课件(第1课时)
- 苏教版四年级数学上册第七单元拓展提优练习
- 中南大学《高等数学》期末试题及答案详解
- 企业应急管理及能力提升培训课件精选
评论
0/150
提交评论