第12章--运算符重载课件.ppt
《第12章--运算符重载课件.ppt》由会员分享,可在线阅读,更多相关《第12章--运算符重载课件.ppt(74页珍藏版)》请在三一办公上搜索。
1、本章要点:,什么是运算符重载一元运算符的重载二元运算符的重载通过友元函数实现重载输出、输入运算符的重载,在前面学习类和对象的时候,我们明确了这样一个概念:定义一个类就是定义一种新类型。因此,对象和变量一样,可以作为函数的参数传递,可以作为函数的返回值的类型,也可以说明对象数组,甚至还可能有类类型的常量。在基本数据类型上,系统提供了许多预定义的运算符,它们以一种简洁的方式工作。例如“+”运算符:intx,y;y=x+y;表示两个整数相加,很简洁。但是,两个字符串合并:charx20,y10;/定义两个字符串类型/strcat(x,y);表达起来就不如“y=x+y;”那样直观简洁。因此,为了表达上
2、的方便,希望已预定义的运算符,也可以在特定类的对象上以新的含义进行解释。如在string类对象x、y的环境下,运算符“+”能被解释为字符串x和y的合并。换言之,希望预定义运算符能被重载,让用户自定义的类也可以使用。,一、为什么要进行运算符重载,C语言中有多种内置的数据类型,例如int、float、double和char等等。对应于每一种类型都有一系列的内置运算符,比如加法运算符“+”和乘法运算符“*”。就拿运算符“+”来说吧,它可以用于int值,也可以用于float,虽然使用相同的运算符,但生成的代码不同,因为整数和浮点数在内存中的表示是不同的。这时,“+”运算符具有两种不同的解释(即实现代码
3、)。也就是说,像“+”这样的运算符在C语言中已被重载。但是,C语言仅支持少量有限的运算符重载。C+语言对重载功能进行了扩充,也允许我们在自己定义的类上添加运算符,允许对已存在的预定义运算符由我们在不同的上下文中做出不同的解释。比如,经过运算符重载,我们可以直接对两个字符串string类对象进行加法运算string x,y;x=x+y;可以直接输出复数类CComplex对象Ccomplex c;cout c;,通过运算符重载,程序代码就显得简洁明了,类对象的使用也方便了。这就是我们重载运算符的目的。第一个基本动作就这么简单,没问题吧?好了,如果第一关没问题,可以继续前进了。先看看下面这段话:因为
4、本书针对C+的入门读者,所以对一些深层次复杂的运算符重载,比如new和delete的重载以及类型转换等等不做介绍,以免倒了你的胃口。这里我们只介绍一下常用的运算符重载的实现,让大家明白运算符重载是怎么回事、如何实现,就算是完成任务了。如果想进一步学习复杂的高级的重载,可以参见别的参考书。运算符重载函数可以作为类的成员函数,也可以作为类的友元函数来实现。下面对这两种不同的实现分别讲述。,通俗地说,重载运算符就是在写函数,用这个运算符函数体对重载的运算符的含义做出新的解释。这里所解释的含义与重载该运算符的类有关,比如,字符串类重载的加运算符“+”,实际上是对两个字符串进行拼接。重载后的运算符还是按
5、这些运算符的表达方式使用。例如,在一个string类中重载了运算符“+”为两个字符串的合并,我们可以这样写:string s1,s2;s1=s1+s2;/合并串s1和串s2,存放到新串s1中。为了把运算符从头到脚地看个明明白白,我们创建一个新类:计数器类CCounter,逐步地根据需求来完善此类,并进一步地解释为什么要重载运算符以及如何来重载。例15.1 创建类CCounter,类CCounter的一个对象可以用来在循环中计数(感到惊奇吧),而且这个类的对象还可以用在其它程序中以实现数字递增、递减或跟踪一些值的地方。,二、以成员函数实现运算符重载,程序清单 C15_01.cpp/类Counte
6、r的简单定义及实现#include using namespace std;class CCounterpublic:CCounter():m_val(0)/缺省构造函数,成员变量m_val初始化为0CCounter()/什么事都不干的析构函数/下面两个函数是私有变量m_val的存取访问函数unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;private:unsigned m_val;main()CCounter counter;cout counter的值是:counter.GetVal()endl;,输出结
7、果counter的值是:0,程序分析:事实上,上面创建的CCounter类是一个“垃圾类”,没有任何用处,只有惟一的一个成员变量m_val,而且被缺省的构造函数初始化为零。用类CCounter创建的对象不能像整型变量那样进行自增和自减运算,也不能进行加法、赋值或者其它的算术操作。更恶劣的是,这个类创建的对象的输出也是一个问题,不能像整型数那样直接用cout进行输出。通过我们即将要学习的运算符重载来对CCounter类进行“教化”,使它能够像一般的整型数一样来进行一系列的算术运算。再次说明,我们只是想通过对类CCounter的逐步改造来讲解运算符重载的知识,至于这个类本身,用处倒不大。,1.重载
8、一元运算符:递增运算符“+”(1)通过添加成员函数Increment(),实现自增功能运算符重载可以使类获得使用这些运算符的“权限”。例如,我们可以通过下面两种方式让类CCounter的对象具有自增运算的功能。一种方式是通过在类CCounter中添加一个实现自增功能的方法Increment(),如下面例15.2:例15.2 给CCounter类添加自增函数Increment()。,程序清单 C15_02.cpp#include using namespace std;class CCounterpublic:CCounter():m_val(0)CCounter()unsigned GetVa
9、l()const return m_val;void SetVal(unsigned x)m_val=x;void Increment()+m_val;/自增函数,将变量的值加1private:unsigned m_val;main()CCounter counter;cout counter的值是:counter.GetVal()endl;counter.Increment();cout 调用自增函数之后,;cout counter的值是:counter.GetVal()endl;,输出结果counter的值是:0调用自增函数之后,counter的值是:1,程序分析:例15.2中,在类CCo
10、unter中添加了自增函数Increment(),虽然它可以正常工作,但是使用起来和运算符“+”比较起来可是差远了,太麻烦了。似乎听见哪有抗议声,哦,原来是上面的程序在喊:“为什么不给我添加+运算符”。别急,当然可以满足它的愿望了,通过重载运算符+就可以实现。,(2)重载前缀运算符“+”1)重载前缀运算符“+”,返回类型为void要重载前缀+运算符,可以通过运算符重载函数实现,我们这里是把运算符重载函数作为类的成员函数实现的,它的语法形式如下:其中,returntype是返回值类型,operator是关键字,“op”是要重载的运算符符号,classname是重载该运算符的类的名称。重载函数的函
11、数名是由关键字operator后面加上要重载的运算符符号组成的,为operator op。这里我们用“op”泛指可被重载的运算符。因此,自增运算符+可以按如下的形式进行重载:void operator+();,returntype classname:operator op(参数表)/相对于该类而定义的操作代码,例15.3 在CCounter类中通过运算符+的重载,实现CCounter类的自增运算+。程序清单 C15_03.cpp/重载运算符+,运算符重载函数作为类CCounter的成员函数#include using namespace std;class CCounterpublic:CC
12、ounter():m_val(0)CCounter()unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;void Increment()+m_val;void operator+()+m_val;/重载运算符+private:unsigned m_val;,main()CCounter counter;cout counter的值是:counter.GetVal()endl;counter.Increment();cout 调用自增函数之后,;cout counter的值是:counter.GetVal()en
13、dl;+counter;cout 使用自增运算符+之后,;cout counter的值是:counter.GetVal()endl;,输出结果counter的值是:0调用自增函数之后,counter的值是:1使用自增运算符+之后,counter的值是:2,程序分析:在上面的程序中,函数:void operator+()+m_val;实现了运算符+的重载。在main()函数中,语句:+counter;对象counter,使用了类CCounter重载的运算符+,这种语法形式与我们期望类CCounter对象所具有的形式非常接近。但是,或许你想让类CCounter对象具有更多附加的功能,比如检查CCo
14、unter类对象是否超出了最大值范围等等。,2)重载运算符“+”,返回一个CCounter类对象,通过创建临时变量实现不知道你是否注意到,我们上面重载的自增运算符有一个很大的缺陷,那就是如果你想把CCounter类对象放在赋值运算符的右侧,那么对不起,编译器会不客气地报错,你不妨试试。把CCounter类对象放在赋值运算符的右侧,例如:CCounter counter2=+counter;这条语句试图建立一个新的CCounter类对象counter2,然后把对象counter自增后的值赋给这个对象。内置的拷贝构造函数将处理赋值运算,但是现在的自增运算符并没有返回一个CCounter类对象,而是
15、返回空类型void,我们不能把一个空类型void对象赋给一个CCounter类对象。那怎么办?下面我们就来解决这个棘手的问题。显然,我们只需要让重载运算符函数返回一个CCounter类对象问题就解决了,这样返回的对象值就可以赋给另一个CCounter类对象了。那么返回哪个对象呢?一种方法是创建一个临时对象,然后返回。,例15.4 在CCounter类中重载运算符+,并返回一个CCounter类型的临时对象。程序清单 C15_04.cpp/重载运算符+,并返回一个临时对象#include using namespace std;class CCounterpublic:CCounter():m_
16、val(0)CCounter()unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;void Increment()+m_val;CCounter operator+();/重载+运算符,返回值为CCounter类型private:unsigned m_val;,CCounter CCounter:operator+()+m_val;CCounter temp;temp.SetVal(m_val);return temp;main()CCounter counter;cout counter的值是:counter
17、.GetVal()endl;counter.Increment();cout 调用自增函数之后,;cout counter的值是:counter.GetVal()endl;+counter;cout 使用自增运算符+之后,;cout counter的值是:counter.GetVal()endl;CCounter counter2=+counter;cout counter2的值是:counter2.GetVal()endl;cout counter的值是:counter.GetVal()endl;,输出结果counter的值是:0调用自增函数之后,counter的值是:1使用自增运算符+之后
18、,counter的值是:2counter2的值是:3counter的值是:3,程序分析:在上面这个版本的程序中,运算符重载函数operator+的返回值为一个CCounter类对象。在函数operator+中,我们创建了一个临时对象temp:CCounter temp;而且通过语句temp.SetVal(m_val);将对象temp的值设置为当前对象的值。临时对象被返回而且赋值给对象counter2。CCounter counter2=+counter;至此,上面的实现好像是很完美了,但是,有一个问题,就是:为什么我们要创建一个临时对象?”,记住:每个临时对象被创建而且使用完之后必须要被销毁这
19、是一个潜在的“奢侈”的操作,要耗费资源,况且对象counter已经存在,并且已经有正确的值,那么为什么不直接返回它呢?我们可以通过使用this指针来解决这个问题。,3)重载运算符“+”,通过this指针返回一个CCounter类对象的引用正如我们在第13章中讨论的那样,this指针是类的所有成员函数的隐含参数,因为运算符重载函数operator+是类的成员函数,所以this指针是该函数的隐含参数。this指针指向对象counter,如果间接引用this指针(*this)则其返回对象counter,对象counter的成员变量m_val已经有正确的值。例15.5 在CCounter重载运算符函数
20、中返回间接引用this指针的值,这样就可以避免创建一个临时对象,从而可以提高程序运行的效率。,程序清单 C15_05.CPP/返回this指针的间接引用#include using namespace std;class CCounterpublic:CCounter():m_val(0)CCounter()unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;void Increment()+m_val;const CCounter,main()CCounter counter;cout counter的值是:c
21、ounter.GetVal()endl;counter.Increment();cout 调用自增函数之后,;cout counter的值是:counter.GetVal()endl;+counter;cout 使用自增运算符+之后,;cout counter的值是:counter.GetVal()endl;CCounter counter2=+counter;cout counter2的值是:counter2.GetVal()endl;cout counter的值是:counter.GetVal()endl;,输出结果counter的值是:0调用自增函数之后,counter的值是:1使用自增
22、运算符+之后,counter的值是:2counter2的值是:3counter的值是:3,程序分析:在上面的程序中,通过间接引用this指针,返回当前对象的引用,并将当前对象的值赋给对象counter2。注意:上面程序中返回的是当前对象的引用,因此就避免了创建多余的临时对象。因为要防止当前的对象值被别的函数改变,所以返回值是const限定的常量引用(回忆一下const限定的使用)。好了,现在类CCounter已经有了一个使用方便,性能卓越的+运算符了。大家自然的会想到前面的+运算符是前缀自增,那后缀自增运算符又该如何重载呢?想的周到,值得表扬。我们下面就看看重载后缀自增运算符如何实现。,(3)
23、重载后缀运算符“+”首先来看看编译器是如何区别前缀自增和后缀自增运算的?按照约定,在运算符重载函数的声明中,提供一个整型数作为函数的参数,就表示重载的是后缀运算符。参数值并没有什么用,它只是用来表明重载的是后缀运算符。在我们重载后缀自增运算符之前,先要彻底搞清楚到底它与前缀自增运算符有什么不同。如果忘记了,请回头去看看前面的C语言部分。前面我们讲到,前缀自增是“先自增,然后再拿来参与运算”,而后缀自增相反,它是“先拿来用,然后变量再自增”。因此,重载前缀运算符只要简单地递增变量的值,然后返回对象本身即可,而后缀运算符必须返回进行自增运算之前的对象的值。为了做到这一点,我们必须创建一个临时对象,
24、用它来存储对象的初始值,然后增加对象的初始值,最后返回临时对象。,让我们通过下面的小例子再简单地回顾一下后缀运算符的使用。m=n+;如果n的值是6,执行完上述语句之后,m的值是6,但是n的值是7。这样,我们返回了变量n原来的值,并且赋给变量m,然后将n的值加1。如果n是一个对象,它的后缀自增运算必须先将对象原来的值(如6)存储到一个临时对象中,然后增加n的值(n的值变为7),最后返回临时对象的值并赋给变量m。注意:因为我们返回的是临时对象,所以必须返回对象的值,而不能是返回引用,这是因为临时对象在函数返回时就超出了它的作用范围,将被销毁,如果返回它的引用,那么这个引用将是一个已经不存在的对象的
25、引用,其后果是不可预料的。,例15.6 在CCounter中实现后缀和前缀自增运算符的重载。程序清单 C15_06.cpp/重载后缀和前缀自增运算符#include using namespace std;class CCounterpublic:CCounter():m_val(0)CCounter()unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;void Increment()+m_val;const CCounter,const CCounter/返回临时对象,main()CCounter count
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 12 运算 重载 课件

链接地址:https://www.31ppt.com/p-4095562.html