第11章77 运算符重载公开课一等奖省优质课大赛获奖课件_第1页
第11章77 运算符重载公开课一等奖省优质课大赛获奖课件_第2页
第11章77 运算符重载公开课一等奖省优质课大赛获奖课件_第3页
第11章77 运算符重载公开课一等奖省优质课大赛获奖课件_第4页
第11章77 运算符重载公开课一等奖省优质课大赛获奖课件_第5页
已阅读5页,还剩72页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第11章运算符重载什么是运算符重载运算符重载方法几个特殊运算符重载自定义类型转换运算符运算符重载实例什么是运算符重载使系统内置运算符能够用于类类型比如:+运算符能够实现2个对象间加。比如:类A对象a1、a2、a3,希望:a3=a1+a2;即:分别把对象a1和a2各个数据组员值对应相加,然后赋给对象a3。问题提出把一些事交给系统去做,用户只要知道相加就可扩充运算符功效增强了C++语言可扩充性使用户定义类更像系统内置类型运算符重载限制不是全部运算符都能重载重载不能改变运算符优先级和结合性重载不能改变运算符操作数个数不能创建新运算符能够重载运算符+

-

*

/

%

^

&

|

~

!

=

<

>

+=

-=

*=

/=

%=

^=

&=

|=

<<

>>

>>=

<<=

==

!=

<=

>=

&&

||

++

--

->*

->

[]

()

new

delete

new[]

delete[]

不能重载运算符

.

.*

::

?:

sizeof第11章运算符重载什么是运算符重载运算符重载方法几个特殊运算符重载自定义类型转换运算符运算符重载实例运算符重载方法运算符重载就是写一个函数解释某个运算符在某个类中含义要使得系统能自动找到重载这个函数,函数名必须要表达出和某个被重载运算符联络。C++中要求,重载函数名为operator@其中,@为要重载运算符。如要重载“+”运算符,该重载函数名为operator+。要重载赋值运算符,函数名为operator=。函数原型

运算符重载不能改变运算符运算对象数。所以,重载函数形式参数个数(包含组员函数隐式指针this)与运算符运算对象数相同运算符重载能够重载成组员函数也能够重载成全局函数实现。重载成全局函数时,最好把此函数设为友员函数假如作为类组员函数,它形式参数个数比运算符运算对象数少1。这是因为组员函数有一个隐含参数this。在C++中,把隐含参数this作为运算符第一个参数。当把一个一元运算符重载成组员函数时,该函数没有形式参数。把一个二元运算符重载成组员函数时,该函数只有一个形式参数,就是右操作数,当前对象是左操作数。重载实例为rational类增加“+”和“*”以及比较重载函数,用以替换现有add和multi函数方案一:重载成组员函数classRational{private: intnum; intden; voidReductFraction();public: Rational(intn=0,intd=1){num=n;den=d;}

Rationaloperator+(constRational&r1)const;

Rationaloperator*(constRational&r1)const; booloperator<(constRational&r1)const; booloperator==(constRational&r1)const; booloperator>(constRational&r1)const; booloperator<=(constRational&r1)const; booloperator>=(constRational&r1)const; booloperator!=(constRational&r1)const; voiddisplay(){cout<<num<<'/'<<den;}}函数实现RationalRational::operator+(constRational&r1)const{Rationaltmp;tmp.num=num*r1.den+r1.num*den;

tmp.den=den*r1.den;tmp.ReductFraction();returntmp;}RationalRational::operator*(constRational&r1)const{Rationaltmp;tmp.num=num*r1.num;

tmp.den=den*r1.den;tmp.ReductFraction();returntmp;}boolRational::operator<(constRational&r1)const{returnnum*r1.den<den*r1.num;}boolRational::operator==(constRational&r1)const{returnnum==r1.num&&den==r1.den;}boolRational::operator>(constRational&r1)const{returnnum*r1.den>den*r1.num;}boolRational::operator<=(constRational&r1)const{returnnum*r1.den<=den*r1.num;}boolRational::operator>=(constRational&r1)const{returnnum*r1.den>=den*r1.num;}boolRational::operator!=(constRational&r1)const{return!(*this==r1);}方案二:重载成友员函数classRational{friendRationaloperator+(constRational&r1,constRational&r2);

friendRationaloperator*(constRational&r1,constRational&r2);friendbooloperator<(constRational&r1,constRational&r2); friendbooloperator==(constRational&r1,constRational&r2); friendbooloperator>(constRational&r1,constRational&r2); friendbooloperator<=(constRational&r1,constRational&r2); friendbooloperator>=(constRational&r1,constRational&r2); friendbooloperator!=(constRational&r1,constRational&r2);private: intnum; intden; voidReductFraction();public: Rational(intn=0,intd=1){num=n;den=d;} voiddisplay(){cout<<num<<'/'<<den;}};函数实现Rationaloperator+(constRational&r1,constRational&r2){Rationaltmp;

tmp.num=r1.num*r2.den+r2.num*r1.den;

tmp.den=r1.den*r2.den;tmp.ReductFraction();returntmp;}Rationaloperator*(constRational&r1,constRational&r2){Rationaltmp;tmp.num=r1.num*r2.num;

tmp.den=r1.den*r2.den;tmp.ReductFraction();returntmp;}其它函数实现略重载后有理数类使用intmain(){Rationalr1(1,6),r2(1,6),r3;r3=r1+r2;r1.display();cout<<"+";r2.display();cout<<"=";r3.display();cout<<endl;r3=r1*r2;r1.display();cout<<"*";r2.display();cout<<"=";r3.display();cout<<endl;return0;}全局函数vs组员函数大多数运算符都能够重载成组员函数或全局函数。赋值(=)、下标([])函数调用(())和组员访问(->)必须重载成组员函数。含有赋值意义运算符,如复合赋值运算符以及++和--,不一定非要定义为组员函数,但最好定义为组员函数。含有两个运算对象运算符最好重载为全局函数,这么能够使得应用愈加灵活。假如把加运算定义成全局函数,r是有理数类对象,则2+r是一个正当表示式。第11章运算符重载什么是运算符重载运算符重载方法几个特殊运算符重载自定义类型转换运算符运算符重载实例几个特殊运算符重载赋值运算符下标运算符函数调用运算符++和—运算符重载重载函数原型设计考虑输入输出运算符重载赋值运算符对任一类,假如用户没有自定义赋值运算符函数,那么系统为其生成一个缺省赋值运算符函数,在对应数据组员间赋值。普通情况下,这个缺省赋值运算符重载函数能满足用户需求。不过,当类含有类型为指针数据组员时,可能会带来一些麻烦。对DoubleArray类对象执行

array1=array2问题会引发内存泄漏使这两个数组元素存放于同一块空间中当这两个对象析构时,先析构对象会释放存放数组元素空间。而当后一个对象析构时,无法释放存放数组元素空间赋值运算符“=”原型赋值运算符只能重载成组员函数函数原型:X&X::operator=(constX&source){//赋值过程}一旦创建了对象x1,x2,能够用x1=x2赋值。DoubleArray类

赋值运算符重载函数DoubleArray&DoubleArray::operator=(constDoubleArray&right){if(this==&right)return*this;delete[]storage;low=right.low;high=right.high;storage=newdouble[high-low+1];for(inti=0;i<=high-low;++i)storage[i]=right.storage[i];//复制数组元素return*this;}赋值运算符重载关键点普通来讲,需要自定义拷贝结构函数类也需要自定义赋值运算符重载函数。在赋值运算符重载函数中,已经将参数值赋值给了当前对象,那为何还需要返回值呢?记住,在C++中,赋值是一个运算,它能够形成一个表示式,而该表示式结果值就是赋给左边对象值。所以,赋值运算符重载函数必须返回赋给左边对象值。赋值运算符重载和拷贝结构函数普通来讲,需要拷贝结构函数类也需要重载赋值运算符定义对象时给对象赋初值调用是拷贝结构函数程序语句部分中赋值语句调用是赋值运算符重载函数几个特殊运算符重载赋值运算符下标运算符函数调用运算符++和—运算符重载重载函数原型设计考虑输入输出运算符重载下标运算符重载能否象普通数组那样经过下标运算操作DoubleArray类对象,这么能够使DoubleArray类更像一个功效内置数组。能够经过重载下标运算符([])来实现下标运算符是二元运算符,第一个运算数是数组名,第二个运算数是下标值下标运算符必须重载成组员函数DoubleArray类[]重载double&DoubleArray::operator[](intindex){if(index<low||index>high){cout<<"下标越界";exit(-1);}returnstorage[index-low];}DoubleArray类使用定义:DoubleArrayarray(20,30);数组输入:for(i=20;i<=30;++i){ cout<<"请输入第"<<i<<"个元素:"; cin>>array[i];}数组输出:for(i=20;i<=30;++i) cout<<array[i]<<'\t';几个特殊运算符重载赋值运算符下标运算符函数调用运算符++和—运算符重载重载函数原型设计考虑输入输出运算符重载函数调用运算符函数调用运算符()是一个二元运算符。它第一个运算对象是函数名,第二个参数是形式参数表。运算结果是函数返回值。一个类重载了函数调用运算符,就能够把这个类对象当做函数来使用函数调用运算符重载函数调用运算符必须重载成组员函数函数调用运算符重载函数原型为函数返回值operator()(形式参数表);函数调用运算符重载实例在DoubleArray类增加一个功效:取数组中一部分元素形成一个新数组比如,在一个下标范围为10到20数组arr中取出下标为第12到15元素,形成一个下标范围为2到5数组存放在数组arr1中,能够调用arr1=arr(12,15,2)。DoubleArrayoperator()(intstart,intend,intlh){ if(start>end||start<low||end>high){cout<<"下标越界";exit(-1);}

DoubleArraytmp(lh,lh+end-start); for(inti=0;i<end-start+1;++i)tmp.storage[i]=storage[start+i-low]; returntmp;}几个特殊运算符重载赋值运算符下标运算符函数调用运算符++和—运算符重载重载函数原型设计考虑输入输出运算符重载“++”和“--”重载++、--:是一元操作符这两个操作符能够是前缀,也能够是后缀。而且前缀和后缀含义是有区分。所以,必须有两个重载函数。问题:两个重载函数有相同原型区分方法:前缀:一元操作符。后缀:二元操作符。“++”和“--”重载cont.组员函数重载++ob重载为:ob.operator++()ob--重载为:ob.operator--(int)友元函数重载++ob重载为:operator++(X&ob)ob--重载为:operator--(X&ob,int)调用时,参数int普通传递给值0。++、--重载实例设计一个会报警计数器类。该计数器从0开始计数,当抵达预先设定好报警值时,计数器会发出报警消息,计数器值不再增加。类定义classCounter{ intvalue;//计数器值 intalarm;//报警值public: Counter(inta){value=0;alarm=a;} Counter&operator++();//前缀++重载 Counteroperator++(int);//后缀++重载 voidprint(){cout<<value<<endl;}};类实现Counter&Counter::operator++(){if(value==alarm)cout<<"已超出报警值\n";else{++value;if(value==alarm)cout<<"已抵达报警值\n"; }return*this;}CounterCounter::operator++(intx){Countertmp=*this;//保留对象修改前状态if(value==alarm)cout<<"已超出报警值\n";else{++value;if(value==alarm)cout<<"已抵达报警值\n"; }returntmp;//返回修改前状态}类使用intmain(){Countercnt(3);//定义一个Counter类对象,报警值为3cnt.print();/显示对象当前值,此时输出为0++cnt;cnt.print();//此时输出为1(++cnt).print();//调用前缀++,输出2(cnt++).print();//调用后缀++,当前对象value已经//加1,报警。但输出是2cnt.print();//输出值为3return0;}几个特殊运算符重载赋值运算符下标运算符函数调用运算符++和—运算符重载重载函数原型设计考虑输入输出运算符重载重载函数原型设计考虑参数设计对于任何函数参数,假如仅需要从参数中读,而不改变它,普通用const引用来传递。只有会修改左值参数运算符,如赋值运算符,左值参数不是常量,所以用地址传递返回值类型设计运算符结果产生一个新值,就需要产生一个作为返回值新对象对于逻辑运算符,人们希望最少得到一个int或bool返回值全部赋值运算符(如,=,+=等)均改变左值,应该能够返回一个刚才改变了左值非常量引用值返回时优化在返回一个对象时,通常有两种写法。如某函数返回一个Rational类对象,它值为两个参数组员对应相加。它两种写法为returnRational(left.num+right.num,left.den+right.den);Rationaltmp;tmp.num=left.num+right.num;tmp.den=left.den+right.den;returntmp;两种写法比较前者意思是“创建一个暂时对象,并返回它”。它只调用了一次结构函数。而后者,先创建了一个对象tmp,这将调用结构函数,然后对tmp赋值,最终返回tmp。而在返回tmp时,又要创建一个暂时对象,并调用拷贝结构函数用tmp对它进行初始化。在函数执行结束时,还要调用析构函数析构tmp。几个特殊运算符重载赋值运算符下标运算符函数调用运算符++和—运算符重载重载函数原型设计考虑输入输出运算符重载输入输出运算符重载输入输出运算符必须被重载成全局函数。输出运算符重载输入运算符重载借助于流插入运算符(>>)和流提取运算符(<<)输入和输出用户自定义类对象输出重载函数原型ostream&operator<<(ostream&os,constClassType&obj){os<<要输出内容;returnos;}实例ostream&operator<<(ostream&os,constRational&obj)//输出重载函数{os<<obj.num<<'/'<<obj.den;returnos;}如定义:Rationalr(2,6);执行cout<<r;结果是1/3。为Rational类重载输出输入输出运算符重载输入输出运算符必须被重载成全局函数。输出运算符重载输入运算符重载借助于流插入运算符(>>)和流提取运算符(<<)输入和输出用户自定义类对象输入重载函数原型istream&operator>>(istream&is,ClassType&obj){is>>要输入内容;returnis;}实例istream&operator>>(istream&in,Rational&obj)//输入重载函数{in>>obj.num>>obj.den;obj.ReductFraction();returnin;}如定义:Rationalr;能够用cin>>r从键盘输入r数据。如输入为:13执行cout<<r;结果是1/3。为Rational类重载输入第11章运算符重载什么是运算符重载运算符重载方法几个特殊运算符重载自定义类型转换运算符运算符重载实例类型转换--系统预定义类型间转换隐式类型转换

※赋值时

※运算时显式类型转换※强制转换法:(类型名)表示式※函数法:类型名(表示式)自定义类型转换运算符类类型能否和其它类类型或内置类型相互转换?内置类型之所以能相互转换是因为系统预先制订了转换规则,并写好了完成转换程序。类类型与其它类类型或内置类型之间怎样转换,编译器预先无法知道。类设计者必须定义转换方法。类型转换内置类型到类类型转换类类型到其它类型转换内置类型到类类型转换利用结构函数进行转换。比如,对于Rational类对象r,能够执行r=2。此时,编译器隐式地调用Rational结构函数,传给它一个参数2。结构函数将结构出一个num=2,den=1Rational类对象,并将它赋给r。explicit结构函数任何单参数结构函数都能够被编译器用来执行隐式转换,即把内置类型转换成对应类类型。在一些情况下,隐式转换是不受欢迎。将单参数结构函数定义为explicit,将告诉编译器不允许执行隐式转换。如将Ratioanal类结构函数定义成explicitRational(intn1=0,intn2=1)则对于Rational类对象r1和r2,执行r1=2+r2;编译器就会报错类型转换内置类型到类类型转换类类型到其它类型转换类类型到内置类型或其它类类型转换能够经过类型转换函数实现类型转换函数必须重载成组员函数类型转换函数格式operator目标类型名()const{…return(结果为目标类型表示式);}类型转换函数特点无参数,无返回值是const函数Rational类到double转换转换函数定义:operatordouble()const{return(double(num)/den);}有了这个函数,我们能够将一个Rational类对象r赋给一个double类型变量x。如r值为(1,3),经过赋值x=r后,x值为0.333333经过运算符重载后Rational类classRational{ friendistream&operator>>(istream&in,Rational&obj); friendostream&operator<<(ostream&os,constRational&obj); friendRationaloperator+(constRational&r1,constRational&r2);friendRationaloperator*(constRational&r1,constRational&r2);private: intnum; intden; voidReductFraction();public: Rational(intn=0,intd=1){num=n;den=d;} operatordouble()const{return(double(num)/den);}};Rational类使用#include<iostream.h>#include"Rational.h"intmain(){Rationalr1,r2,r3,r4;doublex;cout<<"输入r1:";cin>>r1;cout<<"输入r2:";cin>>r2;r3=r1+r2;

cout<<r1<<'+'<<r2<<"="<<r3<<endl;

r3=r1*r2;

cout<<r1<<'*'<<r2<<"="<<r3<<endl;r4=(r1+r2)*r3;

cout<<"(r1+r2)*r3值为:"<<r4<<endl;x=5.5-r1;cout<<"5.5-r1值为:"<<x<<endl;cout<<(r1<r2?r1:r2)<<endl;return0;}输入r1:13输入r2:261/3+1/3=2/31/3*1/3=1/9(r1+r2)*r3值为2/275.5-r1值为:5.166671/3

第11章运算符重载什么是运算符重载运算符重载方法几个特殊运算符重载自定义类型转换运算符运算符重载实例运算符重载实例完善DoubleArray类DoubleArray.h#ifndef_array_h#define_array_h#include<iostream.h>classDoubleArray{ friendostream&operator<<(ostream&os,constDoubleArray&obj); friendistream&operator>>(istream&is,DoubleArray&obj); friendbooloperator==(constDoubleArray&obj1,constDoubleArray&obj2);private:intlow;inthigh;double*storage;public:DoubleArray(intlh=0,intrh=0):low(lh),high(rh){storage=newdouble[high-low+1];} DoubleArray(constDoubleArray&arr);

DoubleArray&operator=(constDoubleArray&right);

double&operator[](intindex);constdouble&operator[](intindex)const;

DoubleArrayoperator()(intstart,intend,intlh);

~DoubleArray(){delete[]storage;}};#endifDoubleArray.cpp//文件名:DoubleArray.cpp//DoubleArray类实现#include<cassert>#include"DoubleArray.h“DoubleArray::DoubleArray(constDoubleArray&arr){low=arr.low;high=arr.high;storage=newdouble[high-low+1];for(inti=0;i<high-low+1;++i)storage[i]=arr.storage[i];}operator=DoubleArray&DoubleArray::operator=(constDoubleArray&a){if(this==&a)return*this;

delete[]storage;low=a.low;high=a.high;storage=newdouble[high-low+1];for(inti=0;i<=high-low;++i)storage[i]=a.storage[i];return*this;}operator[]double&DoubleArray::operator[](intindex){assert(index>=low&&index<=high);returnstorage[index-low];}constdouble&DoubleArray::operator[](intindex)const{assert(index>=low&&index<=high);returnstorage[index-low];}operator<<ostream&operator<<(ostream&os,constDoubleArray&obj){os<<"数组内容为:\n";for(inti=obj.low;i<=obj.high;++i)os<<obj[i]<<'\t';os<<endl;returnos;}operator>>istream&operator>>(istream&is,DoubleArray&obj){cout<<"请输入数组元素["<<obj.low<<","<<obj.high<<"]:\n";for(inti=obj.low;i<=obj.high;++i)is>>obj[i];returnis;}operator==booloperator==(c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论