c课件运算符重载和类重载.ppt_第1页
c课件运算符重载和类重载.ppt_第2页
c课件运算符重载和类重载.ppt_第3页
c课件运算符重载和类重载.ppt_第4页
c课件运算符重载和类重载.ppt_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

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

文档简介

第12章运算符重载和类型重载 主要内容 12 1运算符重载规则12 2类型重载 在C 中有这样的情况 同一个类型或运算符在不同的类中代表不同的意思或者实施不同的运算 这就是面向对象的三大特点之一的多态 函数重载是C 语言中多态的一种表现形式 运算符重载和类型重载是多态的另外两种表现形式 运算符重载是对已有的运算符赋予多重含义 C 中预定义的运算符的操作对象只能是基本数据类型 对于很多用户自定义类型 也需要有类似的运算操作 这就提出了对运算符进行重新定义 赋予已有符号以新功能的要求 同一个运算符作用于不同类型的数据导致不同的行为 12 1运算符重载概述 运算符重载只能对系统提供的已有运算定义新的运算含义 不能创造全新的运算符 同时还不能改变运算符原有的语法结构 操作数个数 优先级和结合性 不能有二义性 不是所有的运算符都能重载 不能重载的运算符有 作用域运算符 条件运算符 直接成员访问运算符 sizeof运算符 解除对指向类成员的指针的引用运算符 运算符重载的关键字是operator 针对一个具体类的已有运算符重载有两种途径 1 将运算符重新定义为类的成员函数 2 将运算符重新定义为类的友元函数 一 运算符重载方法 定义一个重载运算符就像定义一个函数 只是该函数的名字是operator 这里 代表运算符 函数参数表中参数的个数取决于两个因素 1 运算符是一元的 一个参数 还是二元的 两个参数 2 运算符被定义为友元函数 对于一元是一个参数 对于二元是两个参数 还是成员函数 对于一元没有参数 对于二元是一个参数 对象变为左侧参数 1 将运算符重载为类的成员函数 将运算符重载为类的成员函数就是在类中用关键字operator定义一个成员函数 函数名就是重载的运算符 运算符如果重载为类的成员函数 它就可以自由地访问该类的数据成员 运算符重载为类的成员函数的一般格式为 operator 形参表 函数体 其中 类型为运算符重载函数的返回类型 类名为成员函数所属类的类名 即为重载函数名 形参为参加运算的对象或数据 例题12 1 复数的加减运算符重载 includeusingnamespacestd classComplex private floatreal image public Complex floatr 0 floati 0 ComplexAdd constComplex Complex Complex floatr floati real r image i voidComplex Show inti 一般情况下 这里不应该有参数i 本例的目的是为了区分不同的复数 便于观看结果cout0 cout image i endl if image 0 cout image i endl ComplexComplex Add constComplex ComplexComplex operator constComplex intmain Complexc1 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 return0 如果我们把 operator 看成函数名 可以在main 函数中写出如下语句 c3 c1 Add c2 c3 c1 operator c2 这时 operator 就完全是一个函数了 它本质上就是函数 Add 和operator 的作用和功能完全相同 只是表现形式有些区别 例题12 2 一元运算符重载 在Time类 描述时间的类 用三个数据成员分别存放时 分和秒 中重载自加运算符 即一个时间加上n秒后形成一个新的的时间 classTime private inthour minute second public Time inth 0 intm 0 ints 0 其他构造函数省略如Time Time Time Time inth intm ints hour h minute m second s voidTime Show cout hour minute second endl Time TimeTime operator int 返回原来的值 再加Timetemp this second if second 60 second 0 minute if minute 60 minute 0 hour if hour 24 hour 0 returntemp Time intmain Timet1 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 includeusingnamespacestd classString public String p str NULL String constString String String constchar str p str newchar strlen str 1 strcpy p str str String String constString String 赋值运算符重载一般包括以上几个步骤 首先要检查是否自赋值 如果是要立即返回 如果不返回 后面的语句会把自己所指空间删掉 从而导致错误 第二步要释放原有的内存资源 第三步要分配新的内存资源 并复制内容 第四步是返回本对象的引用 如果没有指针操作 则没有第二步操作 赋值运算符与拷贝构造函数在功能上有些类似 都是用一个对象去填另一个对象 但拷贝构造函数是在对象建立的时候执行 赋值运算符是在对象建立之后执行 2 将运算符重载为类的友元函数 二元运算符重载为友元函数的一般格式为 friendoperator operator 函数体 一元运算符重载为友元函数的一般格式为 operator 类名 对象 函数体 其中 函数返回类型为运算符重载函数的返回类型 operator为重载函数名 当重载函数作为友元普通函数时 重载函数不能用对象调用 所以参加运算的对象必须以形参方式传送到重载函数体内 在二元运算符重载函数为友元函数时 形参通常为二个参加运算的对象 例11 4 用友元运算符重载函数实现复数的加减运算 includeusingnamespacestd classComplex private floatreal image public Complex floatr 0 floati 0 friendComplexoperator constComplex Complex Complex floatr floati real r image i voidComplex Show inti cout0 cout image i endl if image 0 cout image i endl Complexoperator constComplex intmain Complexc1 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 return0 例11 5 用友元运算符重载函数实现时间类的 运算符 classTime public Time inth 0 intm 0 ints 0 其他构造函数省略voidShow 显示时 分 秒的成员函数friendTime 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类中重载运算符 使该类对象能加上一个复数形成一个新的复数 能加上一个整数或加上一个实数形成一个新的复数 includeusingnamespacestd classComplex private floatreal image public Complex floatr 0 floati 0 Complexoperator constComplex intmain Complexc1 12 35 c2 20 46 c3 c4 c5 c6 inti 5 floatf 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 return0 在进行运算符重载时 我们要注意 1 重载不能改变该运算符用于内置类型时的含义 正如程序员不能改变运算符 用于两个int型相加时的含义 2 运算符函数的参数至少有一个必须是类的对象或者类的对象的引用 这种规定可以防止程序员运用运算符改变内置类型的函义 3 重载不能改变运算符的优先级 4 重载不能改变运算符的结合律 5 重载不能改变运算符操作数的个数 比如 需要两个操作数 则重载的 也必须要有两个操作数 6 不存在用户定义的运算符 即不能编写目前运算符集合中没有的运算符 不能这样做的部分原因是难以决定其优先级 另一部分原因是没有必要增加麻烦 当一个重载操作符的含义不明显时 给操作取一个名字更好 对于很少用的操作 使用命名函数通常比用操作符更好 如果不是普通操作 没必要为简洁而使用操作符 重载逗号 取地址 逻辑与 逻辑或等操作符通常不是好做法 这些操作符具有有用的内置含义 如果我们定义了自己的版本 就不能再使用这些内置含义 如果类定义了相等操作符 也应该定义不等操作符 同样 如果定义了 为类设计重载操作符的时候 必须选择是将操作符设置为类成员函数还是友元函数 在某些情况下 程序员没得选择 操作符必须是成员函数 有些指导原则有助于决定将操作符设置为类成员还是友元函数 1 赋值 下标 调用 和成员访问箭头 等操作符必须定义为成员 将这些操作符定义为非成员函数在编译时标记为错误 2 像赋值一样 复合赋值操作符通常应定义为类的成员函数 定义成非成员函数不会出现编译错误 3 改变对象状态或与给定类型紧密联系的其他一些操作符 如自增 自减等通常定义为类成员函数 4 对称的操作符 如算术操作符 相等操作符 关系操作符和位操作符 最好定义为非成员函数 istream和ostream是C 的预定义流类 cin是istream的对象 cout是ostream的对象 运算符 由istream重载为提取操作 用于输出和输入基本类型数据 可用重载 运算符 用于输出和输入用户自定义的数据类型 必须定义为类的友元函数 4 重载流插入和流提取运算符 1 输出操作符 的重载输出操作符重载函数形式为 ostream第一个参数和函数的类型都必须是ostream 类型 第二个参数是对要进行输出的类类型的引用 它可以是const 因为一般而言输出一个对象不应该改变对象 返回类型是一个ostream引用 通常是输出操作符所操作的ostream对象 ifndefDATE H INCLUDED defineDATE H INCLUDED includeusingnamespacestd classDate public Date inty intm intd boolisLeapYear voidprint friendostream endif DATE H INCLUDED 例11 7 为Date类重载提取运算符 ex004 cpp include include Date h usingnamespacestd Date Date inty intm intd year y month m day d boolDate isLeapYear return year 4 0 voidDate print cout year month day endl ostream include include Date h usingnamespacestd intmain Dated1 2013 4 1 cout d1 return0 在重载函数中 由于operator 函数是Date类的友元函数 因此在使用Date类的数据成员和成员函数时必须指定对象 一般而言 输出操作符应该输出对象的内容 进行最小限度的格式化 不应该输出换行符 在主函数 main 中 cout的值被传递给output 由于函数返回的是ostream对象的引用 所以在主函数中可以将 连接起来使用 2 输入操作符 的重载输入操作符重载函数形式为 istream与输出操作符类似 输入操作符的第一个形参是一个引用 指向要读的流 并且返回的也是同一个流的引用 第二个形参是对要读入的对象的非const引用 该形参必须为非const 因为输入操作符的目的是将数据读到这个对象中 和输出操作符不同的是输入操作符必须处理错误和文件结束的可能性 例题11 8 重载输入操作符 在上例的基础上加上Date类对象能用 输入数据 classDate public Date year 0 month 0 day 0 Date inty intm intd Date strings boolisLeapYear private intyear intmonth intday friendostream istream intmain Dated1 2013 3 20 cout d2 cout d2 endl return0 输入操作符将读入所期望的值并检查是否发生错误 可能发生的错误有 1 提供的值不正确 如Date类对象中如果输入了字符型数据 读入以及流的后续使用都将失败 2 任何读入都可能碰到输入流中的文件结束或其他一些错误 如果输入操作符检测到输入失败了 则确保对象处于可用和一致的状态是个好做法 如果对象在错误发生之前已经写入了部分信息 这样做就特别重要 因此设计输入操作符时 如果可能 要确定错误恢复措施 这是很重要的 例题11 8中如果

温馨提示

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

评论

0/150

提交评论