




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第四章运算符重载本章要点
介绍运算符重载的概念,指出运算符重载的实质就是函数重载,给出运算符重载函数定义的一般格式。通过对两个复数相加运算符重载的例子,我们要讲解运算符重载函数作为类的成员函数和友元函数的方法。最后分别对双目运算符和单目运算符进行了重载。特别给出单目运算符的前置自增和后置自增的区别。转换构造函数和类型转换函数是本章的难点。本章内容包括:什么是运算符重载运算符重载的方法运算符重载的规则成员函数和友元函数重载重载双目运算符重载单目运算符重载流插入和提取运算符不同类型数据间的转换4.1什么是运算符重载(operatoroverloading)前面介绍了函数重载,同一个函数名可以代表不同功能的函数。运算符也可以重载。5+8,5.8+3.67“+”运算符重载能适用于int、float和double型问题:将“+”运算符重载为复数相加?实现:c3=c1+c2首先,定义一个专门的函数来实现复数相加例4.1通过函数来实现复数相加#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexcomplex_add(Complex&c2);voiddisplay();private:doublereal;doubleimag;};ComplexComplex::complex_add(Complex&c2){Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidComplex::display(){cout<<"("<<real<<","<<imag<<"i)"<<endl;}intmain(){Complexc1(3,4),c2(5,-10),c3;
c3=plex_add(c2);cout<<"c1=";c1.display();cout<<"c2=";c2.display();cout<<"c1+c2=";c3.display();return0;}构造函数重载复数相加函数,返回值类型为类类型调用c.real=real+c2.real;c.imag=imag+c2.imag;c.real=this->real+c2.real;c.imag=this->imag+c2.imag;c.real=c1.real+c2.real;c.imag=c1.imag+c2.imag;c3=plex_add(c2);4.2运算符重载的方法运算符重载是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该函数,即执行表达式就是调用函数的过程。运算符重载是通过定义函数实现的,运算符重载实质上是函数的重载。一般格式:函数类型operator运算符名称(形参表列){对运算符的重载处理}例如:复数加法的函数原型:Complexoperator+(Complex&c1,Complex&c2)函数名例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;};ComplexComplex::operator+(Complex&c2){Complexc;c.real=real+c2.real;c.imag=imag+c2.imag;returnc;}voidComplex::display(){cout<<"("<<real<<","<<imag<<"i)"<<endl;}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;}ComplexComplex::operator+(Complex&c2){returnComplex(real+c2.real,imag+c2.imag);}在执行本句时,系统自动以类对象c2为实参调用c1的运算符重载函数operator+。c1+c2解释为:c1.operator+(c2)说明:重载运算符是由相应函数实现的,何必对运算符重载呢?答:类的声明和使用是分离的,所以对用户方便。运算符重载后,其原有的功能仍保留;C++允许用户自定义新类型,所以必须允许运算符重载,以扩大C++已有运算符的使用范围,使其能作用于类对象,进行赋值运算、关系运算、逻辑运算和输入输出运算。C++没有为类对象重新定义一批新运算符,而是,对现有运算符进行重载。思考题:前例中能否将一个常量和一个复数相加?
c3=3+c2;不正确;
c3=complex(3,0)+c2;正确,复数的虚部为0就是实数常量。4.3重载运算符的规则⑴C++不允许用户定义新的运算符,只能对已有的运算符进行重载;⑵C++允许重载的运算符有:双目运算符+(加),-(减),*(乘),/(除),%(取模)关系运算符==(等于),!=(不等于),<(小于),>(大于),<=(小于等于),>=(大于大于)逻辑运算符||(逻辑或),&&(逻辑与),&(取地址)单目运算符+(正),-(负),*(指针),&(取地址)自增自减运算符++(自增),--(自减)位运算符|(按位或),&(按位与),~(按位取反),^(按位异或),<<(左移),>>(右移)赋值运算符=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=空间申请和释放new,delete,new[],delete[]其他运算符()(函数调用),->(成员访问)->*(成员指针访问),,(逗号),[](下标)不允许重载的运算符只有5个:.(成员访问运算符).*(成员指针访问运算符)::(域运算符)sizeof(长度运算符)?:(条件运算符)⑶重载不能改变运算符运算对象的个数;⑷重载不能改变运算符的优先级;⑸重载不能改变运算符的结合性;⑹重载运算符的函数不能有默认的参数;(否则就可改变参数个数)⑺重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象;防止用户:intoperator+(inta,intb){return(a-b);}如果有两个参数,可以都是类对象,也可以一个是类对象,一个是C++标准类型的数据:Complexoperator+(inta,Complexc){return(Complex(a+c.real,c.image);}⑻用于类对象的运算符一般必须重载,但运算符“=”和“&”例外;⑼应当使重载运算符的功能类似于该运算符作用于标准类型数据时实现的功能。⑽运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也非类的友元函数的普通函数。4.4运算符重载函数作为类成员函数和友元函数例4.2中,operator+作为Complex类中的成员函数。+是双目运算符,但在该例中只有一个参数,事实上有一个参数是隐含的,运算符函数是用this指针隐式地访问类对象的成员。c1+c2解释为:c1.operator+(c2)例4.3将运算符“+”重载为复数加法,重载函数不作为成员函数,放在类外,作Complex的友元函数。#include<iostream.h>//usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler){real=r;imag=0;}Complex(doubler,doublei){real=r;imag=i;}
friendComplexoperator+(Complex&c1,Complex&c2);voiddisplay();private:doublereal;doubleimag;};Complexoperator+(Complex&c1,Complex&c2){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}
voidComplex::display(){cout<<"("<<real<<","<<imag<<"i)"<<endl;}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;}c1+c2解释为:operator+(c1,c2)运算符重载函数可以是:⑴类的成员函数可以通过This指针自由地访问本类的数据成员,少写一个函数参数。成员函数定义:ComplexComplex::operator+(Complex&c2){returnComplex(real+c2.real,imag+c2.imag);}调用:c3=c1+c2;要求:第一个参数c1是一个类对象,而且与运算符重载函数的返回类型相同。将一个复数和一个整数相加,如c1+i;成员函数定义:
ComplexComplex::operator+(int&i){returnComplex(real+i,imag);}调用:c3=c2+i;不能写成:c3=i+c2;此时只能将重载函数作为友元函数,不能作为成员函数。⑵类的友元函数双目运算符重载为友元函数时,在函数的形参表列中必须有两个参数。声明:friendComplexoperator+(Complex&c1,Complex&c2);友元函数定义:Complexoperator+(Complex&c1,Complex&c2){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}调用:c3=c1+c2;形参的顺序任意,不要求第一个参数必须为类对象。要求运算符左侧的操作数与第一个参数对应,运算符右侧的操作数与第二个参数对应。将一个复数和一个整数相加,如i+c1;声明:friendComplexoperator+(Complex&i,Complex&c);友元函数定义:Complexoperator+(Complex&i,Complex&c){returnComplex(i+c.real,c.imag);}调用:c3=i+c2;注意:数学上的交换律不适用调用形式为:c3=c2+i时,再重载运算符“+”为:Complexoperator+(Complex&c,Complex&i){returnComplex(i+c.real,c.imag);}这样,c3=c2+i和c3=i+c2都合法,编译系统会根据表达式的形式选择调用与之匹配的运算符重载函数。一般地,单目运算符重载为成员函数,双目运算符重载为友元函数。⑶既非类的成员函数也非类的友元函数的普通函数普通函数不能访问类的私有成员,所以很少使用。4.5重载双目运算符双目运算符有两个操作数,如:3+5,a=b,i<10等,相应地,重载函数有两个参数。例4.4定义一个字符串string类,用来存放不定长的字符串,重载运算符“==”,“<”,“>”用于定义两个字符串的等于,小于和大于的比较运算。#include<iostream>usingnamespacestd;classString//String是用户自己指定的类名{public:String(){p=NULL;}//默认构造函数String(char*str);//构造函数voiddisplay();private:char*p;};String::String(char*str){p=str;}voidString::display(){cout<<p;}intmain(){Stringstring1("Hello"),string2("Book");string1.display();cout<<endl;string2.display();return0;}框架#include<iostream.h>#include<string.h>classString{public:String(){p=NULL;}String(char*str);
friendbooloperator>(String&string1,String&string2);voiddisplay();private:char*p;};String::String(char*str){p=str;}voidString::display(){cout<<p;}booloperator>(String&string1,String&string2){if(strcmp(string1.p,string2.p)>0)returntrue;elsereturnfalse;}intmain(){Stringstring1("Hello"),string2("Book");cout<<(string1>string2)<<endl;return0;}string1.p指向“hello”string2.p指向“book”运算符重载函数返回值为bool,true的值为1重载运算符“>”#include<iostream.h>#include<string.h>classString{public:String(){p=NULL;}String(char*str);friendbooloperator>(String&string1,String&string2);friendbooloperator<(String&string1,String&string2);friendbooloperator==(String&string1,String&string2);voiddisplay();private:char*p;};重载三个运算符String::String(char*str){p=str;}voidString::display(){cout<<p;}booloperator>(String&string1,String&string2){if(strcmp(string1.p,string2.p)>0)returntrue;elsereturnfalse;}booloperator<(String&string1,String&string2){if(strcmp(string1.p,string2.p)<0)returntrue;elsereturnfalse;}booloperator==(String&string1,String&string2){if(strcmp(string1.p,string2.p)==0)returntrue;elsereturnfalse;}intmain(){Stringstring1("Hello"),string2("Book"),string3("Computer");cout<<(string1>string2)<<endl;cout<<(string1<string3)<<endl;cout<<(string1==string2)<<endl;return0;}#include<iostream.h>#include<string.h>classString{public:String(){p=NULL;}String(char*str);friendbooloperator>(String&string1,String&string2);friendbooloperator<(String&string1,String&string2);friendbooloperator==(String&string1,String&string2);voiddisplay();private:char*p;};String::String(char*str){p=str;}voidString::display(){cout<<p;}booloperator>(String&string1,String&string2){if(strcmp(string1.p,string2.p)>0)returntrue;elsereturnfalse;}booloperator<(String&string1,String&string2){if(strcmp(string1.p,string2.p)<0)returntrue;elsereturnfalse;}booloperator==(String&string1,String&string2){if(strcmp(string1.p,string2.p)==0)returntrue;elsereturnfalse;}voidcompare(String&string1,String&string2){if(operator>(string1,string2)==1){string1.display();cout<<">";string2.display();}elseif(operator<(string1,string2)==1){string1.display();cout<<"<";string2.display();}elseif(operator==(string1,string2)==1){string1.display();cout<<"=";string2.display();}cout<<endl;}intmain(){Stringstring1("Hello"),string2("Book"),string3("Computer"),string4("Hello");compare(string1,string2);compare(string2,string3);compare(string1,string4);return0;}4.6重载单目运算符单目运算符只有一个操作数,如:!a,-b,&c,*p,++I,--i等,相应地,重载函数有一个参数。例4.5有一个Time类,包含数据成员minute和second。要求制作秒表:满60秒进位分,秒归零。#include<iostream>usingnamespacestd;classTime{public:Time(){minute=0;sec=0;}//默认构造函数Time(intm,ints):minute(m),sec(s){}//构造函数重载Timeoperator++();//声明运算符重载函数voiddisplay(){cout<<minute<<":"<<sec<<endl;}private:intminute;intsec;};TimeTime::operator++()//成员函数重载{if(++sec>=60){sec-=60;++minute;}return*this;//返回当前对象值}intmain(){Timetime1(34,0);for(inti=0;i<61;i++) {++time1;time1.display();}return0;}C++约定:在自增、自减运算符重载函数中,没有形参int是前置运算符函数,有形参int是后置运算符函数例4.6在前例的基础上增加对后置运算符的重载#include<iostream>usingnamespacestd;classTime{public:Time(){minute=0;sec=0;}Time(intm,ints):minute(m),sec(s){}Timeoperator++();//声明前置自增运算符
Timeoperator++(int);//声明后置自增运算符voiddisplay(){cout<<minute<<":"<<sec<<endl;}private:intminute;intsec;};TimeTime::operator++(){if(++sec>=60){sec-=60;++minute;}return*this;}TimeTime::operator++(int){Timetemp(*this);sec++;if(sec>=60){sec-=60;++minute;}returntemp;}返回自加后的对象本身返回自加前的对象,然后对象自加intmain(){Timetime1(34,59),time2;cout<<"time1:";time1.display();//time原值++time1;cout<<"++time1:";time1.display();//++time后的值time2=time1++;cout<<"time1++:";time1.display();//time++后的值cout<<"time2:";time2.display();//time++前的值return0;}重载后置运算符时,多了一个int型参数,增加这个参数只是为了与前置自增运算符重载函数区别,没有别的作用,在定义函数时也不必使用此参数,因此可以省写参数名,只需要在括号中写int即可,编译系统在遇到重载后置自增运算符时,则自动调用此函数。4.7重载流插入运算符和流提取运算符C++位运算符<<(左移)和位运算符>>(右移),系统在ostream中进行了重载,用来输入输出C++标准类型的数据。<<重载为流插入运算符,属于istream类库;>>重载为流提取运算符,属于ostream类库;cin和cout分别是istream类和ostream类的对象。凡用到cout<<和cin>>对标准数据类型进行输入输出的,都要#include<iostream>头文件。用户自己定义的类的对象,是不能直接用<<和>>来输入和输出的,所以必须进行重载。对<<和>>重载的函数形式为:
istream&operator>>(istream&,自定义类&);ostream&operator<<(ostream&,自定义类&);第一个参数和函数的类型都必须是istream&或ostream&类型,第二个参数是要进行输入输出操作的类。只能将重载>>和<<的函数作为友元函数或普通函数,而不能定义为成员函数。4.7.1重载流插入运算符“<<”例4.7用运算符<<输出复数#include<iostream.h>classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexoperator+(Complex&c2);
friendostream&operator<<(ostream&,Complex&);private:doublereal;doubleimag;};“+”运算符重载为成员函数“<<”运算符重载为友元函数ComplexComplex::operator+(Complex&c2){returnComplex(real+c2.real,imag+c2.imag);}ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;returnoutput;}intmain(){Complexc1(2,4),c2(6,10),c3;c3=c1+c2;
cout<<c3;return0;}对于:ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real<<"+"<<c.imag<<"i)"<<endl;returnoutput;}cout<<c3解释为:operator<<(cout,c3)形参:&output&c,实参:coutc3函数体相当于:cout<<"("<<c3.real<<"+"<<c3.imag<<"i)"<<endl;returncout;最后的returncout作用是返回当前值,以便连续向输出流插入信息。如果:cout<<c3<<c2;先处理cout<<c3,则(cout<<c3)<<c2;执行得到新的流对象cout,cout(新值)<<c2,运算符的左侧是ostream对象,右侧是Complex类对象c2,再次调用运算符<<重载函数,输出c2的数据。注意:重载的流插入运算符的第二个参数为Complex&c,说明只有在输Complex对象时才能使用本重载运算符,对其他类型的对象无效Cout<<time1;(×)4.7.2重载流提取运算符“>>”C++运算符>>的作用是从一个输入输出流中提取数据。重载的目的是输入类的对象。例4.8在4.7的基础上,增加提取运算符>>,用cin>>输入复数,用cout输出复数。#include<iostream.h>classComplex{public:friendostream&operator<<(ostream&,Complex&);friendistream&operator>>(istream&,Complex&);private:doublereal;doubleimag;};ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real<<"+"<<c.imag<<"i)";returnoutput;}istream&operator>>(istream&input,Complex&c){cout<<"inputrealpartandimaginarypartofcomplexnumber:";input>>c.real>>c.imag;returninput;}cin>>c1解释为:operator>>(cin,c1)形参:&intput&c,实参:cinc1函数体相当于cin>>c.real>>c.imag;returncin;最后的returncin的作用是返回当前值,以便连续从输入流提取数据给程序中的Complex类对象。intmain(){Complexc1,c2;cin>>c1>>c2;cout<<"c1="<<c1<<endl;cout<<"c2="<<c2<<endl;return0;}注意:cin>>c1>>c2;语句,每遇到一次>>就调用一次重载运算符>>函数,因此两次提示输入信息。观察下列结果:ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real;if(c.imag>=0)output<<"+";output<<c.imag<<"i)";returnoutput;}修改:4.8不同类型数据间的转换4.8.1标准类型数据间的转换复习类型转换:inti=6;i=7.5+i;隐式转换int(8.9);显式转换问题:一个自定义的类对象能否转换为标准类型?一个类的对象能否转换为另一个类的对象?答:定义专门的处理函数。4.8.2转换构造函数默认构造函数Complex();//没有参数转换构造函数(conversionconstructorfunction)
Complex(doubler){real=r,image=0};作用是将double型参数r转换成Complex类对象。带参构造函数Complex(doubler,doublei);//用于初始化复制构造函数Complex(Complex&c);//形参是本类对象的引用转换构造函数只能有一个参数参数类型:需要转换的类型函数体:转换方法转换方法:类名(准备转换类型的数据)隐式转换,定义对象时Complexc1(3.5);//建立一个类对象real=3.5,image=0Complex(3.5);//声明无名对象显式转换:若重载了“+”运算符,c,c1为对象c=c1+2.5,//编译错误c=c1+Complex(2.5)//正确将一个学生类对象转换为教师类对象,转换构造函数为:Teacher(Student&s){num=s.num;strcpy(name,);sex=sex;}要求s中的num,name,sex是公有成员,否则不能被类外引用4.8.3类型转换函数用转换构造函数可以将一个指定类型的数据转换为类的对象。但是不能反过来进行。类型转换函数(typeconversionfunction)的作用是将一个类对象转换成另一类型的数据。类型转换函数也称为:类型转换运算符函数、类型转换运算符重载函数、强制类型转换运算符函数。一般形式:operator类型名(){实现转换的语句}operatordouble(){returnreal;}//函数名operatordouble//将一个Complex对象转换为一个double类型数据//其值是Complex类中数据成员real的值类型转换函数不能指定函数类型,函数没有参数。返回值类型是由函数名中指定的类型名来确定。类型转换函数只能作为成员函数,因为转换的主体是本类的对象,不能作为友元函数或普通函数。double类型经过重载后,除了原有的含义外,还获得新的含义——将一个Complex对象转换为double类型数据,并指定了转换方法。转换构造函数和类型转换运算符的共同特点:当需要时,编译系统会自动调用这些函数,建立一个无名的临时对象。例4.9有类型转换函数double,无运算符+重载函数#include<iostream>usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}
operatordouble(){returnreal;}private:doublereal;doubleimag;};intmain(){Complexc1(3,4),c2(5,-10),c3;doubled1,d2=2.5;
d1=d2+c1;cout<<d1<<endl;return0;}类型转换运算符函数自动调用类型转换函数本例特点:表达式:d1=d2+c1;d2double类型数据,c1是Complex类对象,无operator+重载函数。有operatordouble重载函数,调用operatordouble函数,把Complex对象c1转换为double类型数据,建立一个临时的double变量,并与d2相加,最后将一个double型的值赋給d1。例4.10无类型转换函数double,有运算符+重载函数和转换构造函数#include<iostream.h>//usingnamespacestd;classComplex{public:Complex(){real=0;imag=0;}//默认构造函数
Complex(doubler){real=r;imag=0;}//转换构造函数
Complex(doubler,doublei){real=r;imag=i;}//初始化构造函数
friendComplexoperator+(Complexc1,Complexc2);//重载运算符+
friendostream&operator<<(ostream&,Complex&);//重载运算符<<private:doublereal;doubleimag;};Complexoperator+(Complexc1,Complexc2){returnComplex(c1.real+c2.real,c1.imag+c2.imag);}ostream&operator<<(ostream&output,Complex&c){output<<"("<<c.real;if(c.imag>=0)output<<"+";output<<c.imag<<"i)";returnoutput;}intmain(){Complexc1(3,4),c2(5,-10),c3;doubled1,d2=2.5;c1=c2+d2;c3=d2+c2;cout<<c1<<endl;cout<<c3<<endl;return0;}本例特点:表达式:c1
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 养宠物租房合同范例
- 包装物购销合同范例
- 中介合同范本样本
- 农副产品马蹄收购合同范本
- 别墅土建付款合同范本
- 凉山校园保洁合同范本
- 人资服务合同范本
- 全款车抵押合同范本
- 公里桩合同范本
- 劳务派遣未签合同范例
- 合同签订培训课件
- 《灾害的概述》课件
- 国产氟塑料流体控制件生产企业
- 1投影的形成和分类投影的形成投影的分类工程中常用的投影图28课件讲解
- 货物学 课件2.1货物的分类
- 中国糖尿病防治指南(2024版)解读2
- 2025届广东省佛山一中石门中学高考临考冲刺数学试卷含解析
- 2025年奇瑞汽车招聘笔试参考题库含答案解析
- XX县人民医院信息化建设方案数字化整体规划方案
- 2024-2025学年外研版七年级英语上学期期末复习 专题04 阅读理解CD篇20篇 【考题猜想】
- 年产50000吨再生铝精深加工生产线项目可行性研究报告
评论
0/150
提交评论