c课件运算符重载和类重载.ppt

上传人:xin****828 文档编号:14950031 上传时间:2020-08-02 格式:PPT 页数:51 大小:479.81KB
返回 下载 相关 举报
c课件运算符重载和类重载.ppt_第1页
第1页 / 共51页
c课件运算符重载和类重载.ppt_第2页
第2页 / 共51页
c课件运算符重载和类重载.ppt_第3页
第3页 / 共51页
点击查看更多>>
资源描述
第12章 运算符重载和类型重载,主要内容: 12.1 运算符重载规则 12.2 类型重载,在C+中有这样的情况,同一个类型或运算符在不同的类中代表不同的意思或者实施不同的运算,这就是面向对象的三大特点之一的多态。 函数重载是C+语言中多态的一种表现形式,运算符重载和类型重载是多态的另外两种表现形式。,运算符重载是对已有的运算符赋予多重含义。 C+中预定义的运算符的操作对象只能是基本数据类型,对于很多用户自定义类型,也需要有类似的运算操作,这就提出了对运算符进行重新定义,赋予已有符号以新功能的要求。 同一个运算符作用于不同类型的数据导致不同的行为。,12.1 运算符重载概述,运算符重载只能对系统提供的已有运算定义新的运算含义,不能创造全新的运算符,同时还不能改变运算符原有的语法结构、操作数个数、优先级和结合性,不能有二义性。不是所有的运算符都能重载,不能重载的运算符有:作用域运算符(:)、条件运算符(?:)、直接成员访问运算符(.)、sizeof运算符、解除对指向类成员的指针的引用运算符(.*)。 运算符重载的关键字是operator。针对一个具体类的已有运算符重载有两种途径: 1)将运算符重新定义为类的成员函数; 2)将运算符重新定义为类的友元函数。,一、运算符重载方法,定义一个重载运算符就像定义一个函数,只是该函数的名字是operator,这里代表运算符。函数参数表中参数的个数取决于两个因素: 1) 运算符是一元的(一个参数)还是二元的(两个参数)。 2) 运算符被定义为友元函数(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数对象变为左侧参数)。,1.将运算符重载为类的成员函数,将运算符重载为类的成员函数就是在类中用关键字operator定义一个成员函数,函数名就是重载的运算符。运算符如果重载为类的成员函数,它就可以自由地访问该类的数据成员。 运算符重载为类的成员函数的一般格式为: : operator (形参表) 函数体 其中,类型为运算符重载函数的返回类型。类名为成员函数所属类的类名,即为重载函数名。形参为参加运算的对象或数据。,【例题12.1】 复数的加减运算符重载,#include using namespace std; class Complex private: float real,image; public: Complex(float r=0,float i=0); Complex Add(const Complex ,Complex:Complex(float r,float i) real=r; image=i; void Complex:Show(int i) /一般情况下,这里不应该有参数i,本例的目的是为了区分不同的复数,便于观看结果 cout0) cout+imageiendl; if(image0) coutimageiendl; ,Complex Complex:Add(const Complex ,Complex Complex:operator-(const Complex ,int main() Complex c1(12,35),c2(20,46),c3,c4,c5,c6; c1.Show(1); c2.Show(2); c3=c1.Add(c2); c3.Show(3); c4=c1+c2; c4.Show(4); c2+=c1; c2.Show(2); c5=c1-c2; c5.Show(5); return 0; ,如果我们把“operator+”看成函数名,可以在main()函数中写出如下语句: c3=c1.Add(c2); c3=c1.operator+(c2); 这时,operator+就完全是一个函数了(它本质上就是函数),.Add()和operator+的作用和功能完全相同,只是表现形式有些区别。,【例题12.2】一元运算符重载,在Time类(描述时间的类,用三个数据成员分别存放时、分和秒)中重载自加运算符,即一个时间加上n秒后形成一个新的的时间。,class Time private: int hour,minute,second; public: Time(int h=0,int m=0,int s=0); /其他构造函数省略 如Time(Time,Time:Time(int h,int m,int s) hour=h; minute=m; second=s; void Time:Show() couthour:minute:secondendl; ,Time ,Time Time:operator+(int) /返回原来的值,再加 Time temp=*this; second+; if(second=60) second=0; minute+; if(minute=60) minute=0; hour+; if(hour=24) hour=0; return temp; ,Time ,int main() Time t1(10,25,52),t2,t3; t1.Show(); t2=+t1; t1.Show(); t2.Show(); t3=t1+; t3.Show(); t1.Show(); ,对于+(或-)运算符的重载,因为编译器不能区分出+(或-)是前置的还是后置的,所以要加上(int)来区分。 operator+(); /重载前置+ operator+(int); /重载后置+ operator-(); /重载前置- operator-(int); /重载后置-,运算符重载的一些特点如下: (1) 运算符重载函数名必须为:operator。 (2) 运算符的重载是通过运算符重载函数来实现的。对于二元运算符重载函数,函数的参数通常为一个即右操作数,运算符的左操作数为调用重载函数的对象。对于一元运算符重载函数,运算符的左操作数或右操作数为调用重载函数的对象。 (3) 运算符重载函数的返回类型:若对象进行运算后的结果类型仍为原类型,则运算符重载函数的返回类型应为原类型。,【例11.3】 自定义字符串类String中有一个private成员p_str指向一个C格式的字符串,写出其拷贝构造函数,并重载赋值“=”运算符。,#include #include using namespace std; class String public: String()p_str=NULL; String(const String ,String:String(const char *str) p_str=new charstrlen(str)+1; strcpy(p_str,str); String:String(const String ,String ,赋值运算符重载一般包括以上几个步骤,首先要检查是否自赋值,如果是要立即返回,如果不返回,后面的语句会把自己所指空间删掉,从而导致错误;第二步要释放原有的内存资源;第三步要分配新的内存资源,并复制内容;第四步是返回本对象的引用。如果没有指针操作,则没有第二步操作。 赋值运算符与拷贝构造函数在功能上有些类似,都是用一个对象去填另一个对象,但拷贝构造函数是在对象建立的时候执行,赋值运算符是在对象建立之后执行。,2将运算符重载为类的友元函数,二元运算符重载为友元函数的一般格式为: friend operator (, ); operator (, ) 函数体; 一元运算符重载为友元函数的一般格式为: operator (类名 class Complex private: float real,image; public: Complex(float r=0,float i=0); friend Complex operator+( const Complex ,Complex:Complex(float r,float i) real=r; image=i; void Complex:Show(int i) cout0) cout+imageiendl; if(image0) coutimageiendl; ,Complex operator+( const Complex ,int main() Complex c1(12,35),c2(20,46),c3,c4; c1.Show(1); c2.Show(2); c3=c1+c2; c3.Show(3); c4=c1-c2; c4.Show(4); return 0; ,【例11.5】用友元运算符重载函数实现时间类的“+”运算符。,class Time public: Time(int h=0,int m=0,int s=0); /其他构造函数省略 void Show();/显示时:分:秒的成员函数 friend Time,3. 参数和返回值,1) 对于任何函数参数,如果仅需要从参数中读而不改变它,缺省地应当按const引用来传递它。普通算术运算符(像+和-号等)和布尔运算符不会改变参数,所以以const引用传递是使用的主要方式。当函数是一个类成员的时候,就转换为const成员函数。只是对于会改变左侧参数的赋值运算符(像+ =)和运算符=,左侧参数才不是常量( constant ),但因为参数将被改变,所以参数仍然按地址传递。 2) 应该选择的返回值取决于运算符所期望的类型。如果运算符的效果是产生一个新值,将需要产生一个作为返回值的新对象。,3) 所有赋值运算符改变左值。为了使得赋值结果用于链式表达式(像A = B = C),应该能够返回一个刚刚改变了的左值的引用。但这个引用应该是const还是nonconst呢?虽然我们是从左向右读表达式A = B = C,但编译器是从右向左分析这个表达式,所以并非一定要返回一个nonconst值来支持链式赋值。然而人们有时希望能够对刚刚赋值的对象进行运算,例如(A = B). foo( ),这是B赋值给A后调用foo( )。因此所有赋值运算符的返回值对于左值应该是nonconst引用。 4) 对于逻辑运算符,人们希望至少得到一个int返回值,最好是bool返回值。(在大多数编译器支持C + +内置bool类型之前开发的库函数使用int或typedef等价物)。 5) 当有不同类型的参数时,要注意参数的自动类型转换(称为隐式类型转换),隐式类型转换在很多地方可以简化程序的书写,但是也可能留下隐患。,【例11.6】在Complex类中重载运算符+,使该类对象能加上一个复数形成一个新的复数,能加上一个整数或加上一个实数形成一个新的复数。,#include using namespace std; class Complex private: float real,image; public: Complex(float r=0,float i=0); Complex operator+(const Complex ,int main() Complex c1(12,35),c2(20,46),c3,c4,c5,c6; int i=5; float f=7.7; c1.Show(1); c2.Show(2); c3=c1+i; /编译正确 c3.Show(3); c4=c1+f; /编译正确 c4.Show(4); c5=c1+1.5; /编译错误,可用c5=c1+(int)1.5;或者 c5=c1+(float)1.5; c5.Show(5); return 0; ,在进行运算符重载时,我们要注意: 1)重载不能改变该运算符用于内置类型时的含义,正如程序员不能改变运算符+用于两个int型相加时的含义。 2)运算符函数的参数至少有一个必须是类的对象或者类的对象的引用,这种规定可以防止程序员运用运算符改变内置类型的函义。 3)重载不能改变运算符的优先级。 4)重载不能改变运算符的结合律。 5)重载不能改变运算符操作数的个数。比如+需要两个操作数,则重载的+也必须要有两个操作数。 6)不存在用户定义的运算符,即不能编写目前运算符集合中没有的运算符。不能这样做的部分原因是难以决定其优先级,另一部分原因是没有必要增加麻烦。,当一个重载操作符的含义不明显时,给操作取一个名字更好。对于很少用的操作,使用命名函数通常比用操作符更好。如果不是普通操作,没必要为简洁而使用操作符。 重载逗号、取地址、逻辑与、逻辑或等操作符通常不是好做法。这些操作符具有有用的内置含义,如果我们定义了自己的版本,就不能再使用这些内置含义。 如果类定义了相等操作符,也应该定义不等操作符!=。同样,如果定义了,=,=)。,为类设计重载操作符的时候,必须选择是将操作符设置为类成员函数还是友元函数。在某些情况下,程序员没得选择,操作符必须是成员函数。有些指导原则有助于决定将操作符设置为类成员还是友元函数: 1)赋值(=)、下标()、调用(( ))和成员访问箭头(-)等操作符必须定义为成员,将这些操作符定义为非成员函数在编译时标记为错误。 2)像赋值一样,复合赋值操作符通常应定义为类的成员函数。定义成非成员函数不会出现编译错误。 3)改变对象状态或与给定类型紧密联系的其他一些操作符,如自增、自减等通常定义为类成员函数。 4)对称的操作符,如算术操作符、相等操作符、关系操作符和位操作符,最好定义为非成员函数。,istream 和 ostream 是 C+ 的预定义流类,cin 是 istream 的对象,cout 是 ostream 的对象。运算符 由 istream 重载为提取操作, 用于输出和输入基本类型数据。可用重载 运算符 ,用于输出和输入用户自定义的数据类型,必须定义为类的友元函数。,4. 重载流插入和流提取运算符,1)输出操作符的重载 输出操作符重载函数形式为: ostream 第一个参数和函数的类型都必须是ostream class Date public: Date(int y,int m,int d); bool isLeapYear(); void print(); friend ostream #endif / DATE_H_INCLUDED,【例11.7】为Date类重载提取运算符(ex004.cpp),#include #include Date.h using namespace std; Date:Date(int y,int m,int d) year=y; month=m; day=d; bool Date:isLeapYear() return (year%4=0 ,void Date:print() cout year- month- dayendl; ostream ,#include #include Date.h using namespace std; int main() Date d1(2013,4,1); coutd1; return 0; ,在重载函数中,由于operator()函数是Date类的友元函数,因此在使用Date类的数据成员和成员函数时必须指定对象。一般而言,输出操作符应该输出对象的内容,进行最小限度的格式化,不应该输出换行符。在主函数(main)中, cout的值被传递给output。由于函数返回的是ostream对象的引用,所以在主函数中可以将”连接起来使用。,2输入操作符的重载 输入操作符重载函数形式为: istream 与输出操作符类似,输入操作符的第一个形参是一个引用,指向要读的流,并且返回的也是同一个流的引用。第二个形参是对要读入的对象的非const 引用,该形参必须为非const,因为输入操作符的目的是将数据读到这个对象中。和输出操作符不同的是输入操作符必须处理错误和文件结束的可能性。,【例题11.8】重载输入操作符,在上例的基础上加上Date类对象能用“”输入数据。,class Date public: Date()year=0;month=0;day=0; Date(int y,int m,int d); Date(string s); bool isLeapYear(); private: int year; int month; int day; friend ostream,istream ,int main() Date d1(2013,3,20); coutd2; coutd2endl; return 0; ,输入操作符将读入所期望的值并检查是否发生错误。可能发生的错误有: 1) 提供的值不正确。如Date类对象中如果输入了字符型数据,读入以及流的后续使用都将失败。 2)任何读入都可能碰到输入流中的文件结束或其他一些错误。 如果输入操作符检测到输入失败了,则确保对象处于可用和一致的状态是个好做法。如果对象在错误发生之前已经写入了部分信息,这样做就特别重要。因此设计输入操作符时,如果可能,要确定错误恢复措施,这是很重要的。例题11.8中如果输入出现错误,将对象中的数据成员都设置为0,使得对象仍然处于可用状态,同时也不会产生令人误解的结果。,12.2类型重载,C+中提供了类型转换函数,可以将一种类类型对象转换成另一种类类型的对象,这就是类型重载。类型转换函数必须由用户在类中定义为成员函数,其一般格式为: class public: operator ( ); ; :operator () 函数体; 其中operator 为转换函数的函数名,转换函数的作用是将类型1的对象转换成类型2的对象。类中类型转换函数必须是非静态的成员函数,不能定义成友元函数,无返回值类型且不带参数。,【例11.9】定义一个时间类,类中数据成员为时、分、秒。编写类型转换函数,将时、分、秒变成一个以秒为单位的等价实数。,#include using namespace std; class Time private: int hour,minute,second; public: Time(int h=0,int m=0,int s=0); void Show();/显示时:分:秒的成员函数 operator float(); ; Time:Time(int h,int m,int s) hour=h; minute=m; second=s; ,void Time:Show() couthour:minute:secondendl; Time:operator float() float sec; sec=hour*3600+minute*60+second; /coutsecond=secendl; return sec; ,int main() float s1,s2,s3; Time t(10,15,20); s1=t; s2=float(t); t.Show(); s3=(float)t; couts1=s1ts2=s2ts3= s3endl; ,练习题: 自定义数组Array类,重载运算符和.,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!