C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载

上传人:E**** 文档编号:89494233 上传时间:2019-05-25 格式:PPTX 页数:55 大小:569.90KB
返回 下载 相关 举报
C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载_第1页
第1页 / 共55页
C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载_第2页
第2页 / 共55页
C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载_第3页
第3页 / 共55页
C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载_第4页
第4页 / 共55页
C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载_第5页
第5页 / 共55页
点击查看更多>>
资源描述

《C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载》由会员分享,可在线阅读,更多相关《C++程序设计与实践 教学课件 ppt 作者 白忠建 chapter07 运算符重载(55页珍藏版)》请在金锄头文库上搜索。

1、C+程序设计与实践,第七章 运算符重载 电子科技大学信息与软件工程学院 白忠建,第七章 运算符重载,本章要点 运算符重载的原理和使用。通过运算符重载,用户自定义的类类型可以参与标准类型相似的各种的运算。运算符重载的实质是函数重载。 常用运算符的重载。其中+和-运算符作为前缀和后缀重载有不同的形式。 特殊运算符的重载。为特别目的可以重载流、类类型转换、指针、()和运算符。,7.1 问题引入,高级程序设计语言的一种突出的能力就是能够让用户自定义抽象数据类型。同时,还允许用户在自定义类型上定义运算,其中包括赋予语言内建运算新的含义。这扩展了高级程序设计语言的功能,使其能处理更加复杂的问题。,7.1

2、问题引入,然而一个横在程序员面前的难题是,如何使用常规运算符去处理新类型的运算。常规运算符表达简单的操作,很直观,例如,表达式 data1 + data2 * data3 就比 multiply data2 by data3 and add the result to data1 要直观得多。,7.1 问题引入,但问题是,类似于+、*这样的运算符只能对于语言内建的类型(的数据)进行操作。而对于用户自定义类型的数据,编译器将不知道程序员要做什么。举个例子来说,设有如下代码,试图用输出流运算符直接作用在矩形类对象之上: Rectangle rect(10, 20); cout rect endl;

3、 如果没有特别编码,那么编译器将“不明白”运算符作用在类对象上有什么含义。,7.1 问题引入,以复数为例来说,它不是C+的内建类型,因此程序员往往会编写一个类来描述复数类型,同时编写一个全局友元函数add()来完成两个复数的加法运算,另一个全局友元函数assign()来完成两个复数对象的赋值。 提问:请大家设计一个复数类以及运算。,class complex private: double real, imag; public: complex(double r = 0.0, double i = 0.0) : real(r), imag(i) friend complex add(const

4、 complex ,complex add(const complex ,7.1 问题引入,这样,两个复数相加就会用如下代码完成: complex c1(1.0, 2.0), c2(3.0, 4.0), c3; assign(c3, add(c1, c2); 显然,这种函数式的运算多少显得有些别扭,明显不如赋值语句 c3 = c1 + c2; 直观清晰。然而问题是,如果这样做,那么编译器会因为complex不是内建类型而不能理解+运算符直接作用在两个复数类对象上有什么特殊含义。那么该怎么做呢?,7.2 运算符的重载形式,在C+中,很多的运算符被当做是函数,这称为“运算符函数(operator

5、function)”,设运算符为,那么它对应的运算符函数的原型可以形式化地表示为: 返回值类型 operator (参数列表); 这样,我们就可以像重载普通函数一样进行运算符函数的重载。 与普通函数一样,运算符重载函数应该有返回类型和参数。一些特殊的运算符函数如类型转换运算符不能指定返回值类型。此外,返回值和参数的设定必须与重载的运算符的含义相匹配。,7.2 运算符的重载形式,7.2.1运算符重载的语法 在学习语法之前,我们先对操作数的概念作出定义,以便读者理解。 在单目运算oprd或oprd中,oprd称为“操作数”; 在双目运算oprdl oprdr中,oprd1称为“左操作数”,oprd

6、r称为“右操作数” 在绝大多数情况下,参与重载运算的操作数(至少其中一个)是一个类对象,而重载的运算函数与这个类相关。,7.2 运算符的重载形式,运算符作为类的成员重载 现在我们来为List重载的+=运算符,用于取代push_back()完成添加操作。在编写重载代码之前,我们还是先来研究一下+=运算符的特点。 类似于+=这样的含有赋值操作的运算符有这样的特点: 是双目运算符; 运算符结果反映在了左操作数上,而不是产生一个新结果; 运算的结果可以作为左值使用。,7.2 运算符的重载形式,class List /简化版 private: struct Node QUADPTR quad; Node

7、 * next; *head, *tail; public: List(const List,首先,运算符函数+=是类的成员。,其次,函数的参数是右操作数;而左操作数是启动+=函数的对象本身。,最后,push_back()返回左操作数对象本身的引用,然后再由+=函数返回引用,这样就能是返回结果当做左值使用。,List list; Rectangle rect; Square sqr; list += reinterpret_cast(,list.operator+=(reinterpret_cast(,7.2 运算符的重载形式,2. 运算符作为类的友元重载 如果我们再打算为List类重载+运算

8、符,那么情况将有所不同。类似于+这样的双目运算有这样的特性: 参与运算的两个操作数都不会改变; 运算的结果是个新产生的值,并且这个值不能作为左值。 提问:+函数可以作为成员重载吗? 为什么?,7.2 运算符的重载形式,因此,这样的运算符最好作为友元重载。例如:,class List private: struct Node QUADPTR quad; Node * next; *head, *tail; public: List(const List,List operator+(const List ,返回一个临时对象(匿名、常量)。该对象不能作为左值。,两个操作数作为常量参数,因此都不能改

9、变。,7.2 运算符的重载形式,表达式 list + reinterpret_cast(,左边无限定的:运算符说明operator+是全局函数。,隐式调用,显式调用,7.2 运算符的重载形式,C+程序设计的重要基础是类和对象,允许用户自己定义新的类型。如果为了解决这个问题,C+为用户自定义的类对象另外提供一批功能相似的新的运算符,则需要用户记忆更多的运算符及其使用规则。而C+允许重载现有的运算符,使这些简单易用、众所周知的运算符能够直接作用于用户自定义的类对象,扩大了运算符的作用范围。,7.2 运算符的重载形式,7.2.2 重载运算符规则 1. 重载运算符规则 1)大多数系统预定义的运算符可以

10、通过运算符重载函数定义它们对用户定义类型进行操作的新的含义。只有以下少数的C+运算符不能重载: : (作用域解析运算符) ?: (条件运算符) . (成员选择运算符) .* (成员选择运算符),7.2 运算符的重载形式,2)重载运算符时: 不能改变它们的优先级 不能改变它们的结合性 不能改变这些运算符所需操作数的数目 例如,不能利用重载的优势提升+运算符的优先级,使+运算限于*或者/运算符发生;而+运算符的结合性是从左至右的,不能将这个顺序颠倒过来;此外,+运算需要两个操作数参与(即函数有两个参数),因此不能只提供一个。,7.2 运算符的重载形式,3)重载运算符的函数不能有缺省的参数,否则就改

11、变了运算符所需要的操作数的数目。 4)重载的运算符必须和用户自定义的类对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。也就是说,参数不能全部是C+的标准类型,以防止用户修改用于标准类型数据的运算符的性质。例如: 2 + 3永远都被被编译器解释为两个整数相加,而不能有别的含义。,7.2 运算符的重载形式,5)用于类对象的运算符一般必须重载,只有两个运算符:赋值运算符=和地址运算符&可以不必重载。但是要提醒大家,赋值操作可能会比较复杂,因此建议大家还是要为类重载赋值=运算符。 6)应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能,或者其含义显而易见。如果不能建立运算

12、符的这种习惯用法,应该采用函数调用方法,以免造成阅读困难。,7.2 运算符的重载形式,5)用于类对象的运算符一般必须重载,只有两个运算符:赋值运算符=和地址运算符&可以不必重载。但是要提醒大家,赋值操作可能会比较复杂,因此建议大家还是要为类重载赋值=运算符。 6)应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能,或者其含义显而易见。如果不能建立运算符的这种习惯用法,应该采用函数调用方法。 7)重载的运算符函数不能是类的静态成员。,7.2 运算符的重载形式,2. 重载运算 1)运算符重载为成员还是友元的建议,7.2 运算符的重载形式,2)作为成员重载的单目运算符没有参数(后缀

13、+和-是例外),运算符作用在操作数自身之上。作为成员重载的双目运算符(主要是复合赋值运算符)有一个参数,这个参数就是右操作数;而产生的结果反映在左操作数上。作为友元重载的双目运算符有两个参数(即左右操作数),这两个参数中至少有一个是将该运算符函数作为友元对待的类的对象。,7.2 运算符的重载形式,3)如果运算不改变参数的值,那么函数的参数最好是常量引用;否则,就应该是无约束引用。例如所有的算术运算符,它们不会改变两个参数的值,因此这两个参数最好就是常量引用;而流运算符虽然是双目的,但要改变左操作数(是一个流对象)的状态,因此流运算符函数的流对象参数(其为左操作数)只能是无约束引用。,7.2 运

14、算符的重载形式,4)如果运算要产生一个新值,那么函数的返回值最好是结果对象的值(既不是指针也不是引用)。例如,所有的双目算术运算都会产生一个新值,因此这些重载的运算符函数都最好返回一个新产生的值对象。显然,这会引起复制构造函数的调用。,7.2 运算符的重载形式,5)如果运算结果不是产生一个新值,而是改变(其中一个,最常见的是左操作数)参数对象的内部状态,那么函数就应该返回这个参数对象的引用。而这个参数本身也就不能是常量了。例如,所有含有赋值操作的运算符,包括+和-运算,都会改变左操作数参数的内部状态,因此这些操作的返回值应该是左操作数对象的引用。,7.2 运算符的重载形式,6)对于关系和逻辑运

15、算符,它们应该产生一个bool类型的结果。如果使用的编译器不支持bool类型,那么应该返回一个替代的整型值:1表示真,0表示假。 7)如果作为成员重载的运算只是读取对象的属性而不会改变它们,那么建议将该函数设为常成员。,7.3 常用运算符的重载,7.3.1 赋值运算符的重载 两个同类对象之间的复制有两条途径可走: 一是可以在定义对象时利用复制构造函数完成,例如: Rectangle r1(5, 7), r2(r1); 提问:r1通过什么途径复制到r2?,7.3 常用运算符的重载,复制的第二条途径就是在程序代码中更常见到的赋值操作。例如: Rectangle r1(5, 7), r2; r2 =

16、 r1; 提问:这种复制方式与前面的一样吗?,答案:不一样。实际上,编译器并不确切明白赋值号作用在两个对象上有什么确切含义。不过有一点编译器是可以确定的:赋值的意义就是让两个对象变得“一样”。因此,在这个层面上,编译器可谓是“擅作主张”,不提示程序员这里有什么问题,而是采用了最直接的方式完成两个对象间的赋值:逐成员(静态数据成员除外)复制。基于此,我们可以这么说,编译器为类隐式重载了一个赋值运算符,这个重载函数用了最直接简明的方式完成操作。,7.3 常用运算符的重载,在多数情况下,隐式重载的赋值运算符函数工作得很好。但在某些特殊场合,例如需要深复制的场合,赋值操作可能会出现问题。所以,在这种情况下,显式地为类提供重载的赋值运算符是非常明智的选择。 赋值运算符是一个典型的双目运算符,它的左操作数是个左值,右操作数却是左右值不限。因此,赋值运算符函数最好(其实是只能)作为类的成员重载,其唯一的参数最好是右值对象的常量引用,而其返回值应该是左值对象的引用。,Rectangle ,7.3 常用运算

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号