欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    第12章--运算符重载课件.ppt

    • 资源ID:4095562       资源大小:223KB        全文页数:74页
    • 资源格式: PPT        下载积分:16金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要16金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    第12章--运算符重载课件.ppt

    本章要点:,什么是运算符重载一元运算符的重载二元运算符的重载通过友元函数实现重载输出、输入运算符的重载,在前面学习类和对象的时候,我们明确了这样一个概念:定义一个类就是定义一种新类型。因此,对象和变量一样,可以作为函数的参数传递,可以作为函数的返回值的类型,也可以说明对象数组,甚至还可能有类类型的常量。在基本数据类型上,系统提供了许多预定义的运算符,它们以一种简洁的方式工作。例如“+”运算符:intx,y;y=x+y;表示两个整数相加,很简洁。但是,两个字符串合并:charx20,y10;/定义两个字符串类型/strcat(x,y);表达起来就不如“y=x+y;”那样直观简洁。因此,为了表达上的方便,希望已预定义的运算符,也可以在特定类的对象上以新的含义进行解释。如在string类对象x、y的环境下,运算符“+”能被解释为字符串x和y的合并。换言之,希望预定义运算符能被重载,让用户自定义的类也可以使用。,一、为什么要进行运算符重载,C语言中有多种内置的数据类型,例如int、float、double和char等等。对应于每一种类型都有一系列的内置运算符,比如加法运算符“+”和乘法运算符“*”。就拿运算符“+”来说吧,它可以用于int值,也可以用于float,虽然使用相同的运算符,但生成的代码不同,因为整数和浮点数在内存中的表示是不同的。这时,“+”运算符具有两种不同的解释(即实现代码)。也就是说,像“+”这样的运算符在C语言中已被重载。但是,C语言仅支持少量有限的运算符重载。C+语言对重载功能进行了扩充,也允许我们在自己定义的类上添加运算符,允许对已存在的预定义运算符由我们在不同的上下文中做出不同的解释。比如,经过运算符重载,我们可以直接对两个字符串string类对象进行加法运算string x,y;x=x+y;可以直接输出复数类CComplex对象Ccomplex c;cout c;,通过运算符重载,程序代码就显得简洁明了,类对象的使用也方便了。这就是我们重载运算符的目的。第一个基本动作就这么简单,没问题吧?好了,如果第一关没问题,可以继续前进了。先看看下面这段话:因为本书针对C+的入门读者,所以对一些深层次复杂的运算符重载,比如new和delete的重载以及类型转换等等不做介绍,以免倒了你的胃口。这里我们只介绍一下常用的运算符重载的实现,让大家明白运算符重载是怎么回事、如何实现,就算是完成任务了。如果想进一步学习复杂的高级的重载,可以参见别的参考书。运算符重载函数可以作为类的成员函数,也可以作为类的友元函数来实现。下面对这两种不同的实现分别讲述。,通俗地说,重载运算符就是在写函数,用这个运算符函数体对重载的运算符的含义做出新的解释。这里所解释的含义与重载该运算符的类有关,比如,字符串类重载的加运算符“+”,实际上是对两个字符串进行拼接。重载后的运算符还是按这些运算符的表达方式使用。例如,在一个string类中重载了运算符“+”为两个字符串的合并,我们可以这样写:string s1,s2;s1=s1+s2;/合并串s1和串s2,存放到新串s1中。为了把运算符从头到脚地看个明明白白,我们创建一个新类:计数器类CCounter,逐步地根据需求来完善此类,并进一步地解释为什么要重载运算符以及如何来重载。例15.1 创建类CCounter,类CCounter的一个对象可以用来在循环中计数(感到惊奇吧),而且这个类的对象还可以用在其它程序中以实现数字递增、递减或跟踪一些值的地方。,二、以成员函数实现运算符重载,程序清单 C15_01.cpp/类Counter的简单定义及实现#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;,输出结果counter的值是:0,程序分析:事实上,上面创建的CCounter类是一个“垃圾类”,没有任何用处,只有惟一的一个成员变量m_val,而且被缺省的构造函数初始化为零。用类CCounter创建的对象不能像整型变量那样进行自增和自减运算,也不能进行加法、赋值或者其它的算术操作。更恶劣的是,这个类创建的对象的输出也是一个问题,不能像整型数那样直接用cout进行输出。通过我们即将要学习的运算符重载来对CCounter类进行“教化”,使它能够像一般的整型数一样来进行一系列的算术运算。再次说明,我们只是想通过对类CCounter的逐步改造来讲解运算符重载的知识,至于这个类本身,用处倒不大。,1.重载一元运算符:递增运算符“+”(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 GetVal()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中,在类CCounter中添加了自增函数Increment(),虽然它可以正常工作,但是使用起来和运算符“+”比较起来可是差远了,太麻烦了。似乎听见哪有抗议声,哦,原来是上面的程序在喊:“为什么不给我添加+运算符”。别急,当然可以满足它的愿望了,通过重载运算符+就可以实现。,(2)重载前缀运算符“+”1)重载前缀运算符“+”,返回类型为void要重载前缀+运算符,可以通过运算符重载函数实现,我们这里是把运算符重载函数作为类的成员函数实现的,它的语法形式如下:其中,returntype是返回值类型,operator是关键字,“op”是要重载的运算符符号,classname是重载该运算符的类的名称。重载函数的函数名是由关键字operator后面加上要重载的运算符符号组成的,为operator op。这里我们用“op”泛指可被重载的运算符。因此,自增运算符+可以按如下的形式进行重载:void operator+();,returntype classname:operator op(参数表)/相对于该类而定义的操作代码,例15.3 在CCounter类中通过运算符+的重载,实现CCounter类的自增运算+。程序清单 C15_03.cpp/重载运算符+,运算符重载函数作为类CCounter的成员函数#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;void operator+()+m_val;/重载运算符+private:unsigned m_val;,main()CCounter counter;cout counter的值是:counter.GetVal()endl;counter.Increment();cout 调用自增函数之后,;cout counter的值是:counter.GetVal()endl;+counter;cout 使用自增运算符+之后,;cout counter的值是:counter.GetVal()endl;,输出结果counter的值是:0调用自增函数之后,counter的值是:1使用自增运算符+之后,counter的值是:2,程序分析:在上面的程序中,函数:void operator+()+m_val;实现了运算符+的重载。在main()函数中,语句:+counter;对象counter,使用了类CCounter重载的运算符+,这种语法形式与我们期望类CCounter对象所具有的形式非常接近。但是,或许你想让类CCounter对象具有更多附加的功能,比如检查CCounter类对象是否超出了最大值范围等等。,2)重载运算符“+”,返回一个CCounter类对象,通过创建临时变量实现不知道你是否注意到,我们上面重载的自增运算符有一个很大的缺陷,那就是如果你想把CCounter类对象放在赋值运算符的右侧,那么对不起,编译器会不客气地报错,你不妨试试。把CCounter类对象放在赋值运算符的右侧,例如:CCounter counter2=+counter;这条语句试图建立一个新的CCounter类对象counter2,然后把对象counter自增后的值赋给这个对象。内置的拷贝构造函数将处理赋值运算,但是现在的自增运算符并没有返回一个CCounter类对象,而是返回空类型void,我们不能把一个空类型void对象赋给一个CCounter类对象。那怎么办?下面我们就来解决这个棘手的问题。显然,我们只需要让重载运算符函数返回一个CCounter类对象问题就解决了,这样返回的对象值就可以赋给另一个CCounter类对象了。那么返回哪个对象呢?一种方法是创建一个临时对象,然后返回。,例15.4 在CCounter类中重载运算符+,并返回一个CCounter类型的临时对象。程序清单 C15_04.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;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.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使用自增运算符+之后,counter的值是:2counter2的值是:3counter的值是:3,程序分析:在上面这个版本的程序中,运算符重载函数operator+的返回值为一个CCounter类对象。在函数operator+中,我们创建了一个临时对象temp:CCounter temp;而且通过语句temp.SetVal(m_val);将对象temp的值设置为当前对象的值。临时对象被返回而且赋值给对象counter2。CCounter counter2=+counter;至此,上面的实现好像是很完美了,但是,有一个问题,就是:为什么我们要创建一个临时对象?”,记住:每个临时对象被创建而且使用完之后必须要被销毁这是一个潜在的“奢侈”的操作,要耗费资源,况且对象counter已经存在,并且已经有正确的值,那么为什么不直接返回它呢?我们可以通过使用this指针来解决这个问题。,3)重载运算符“+”,通过this指针返回一个CCounter类对象的引用正如我们在第13章中讨论的那样,this指针是类的所有成员函数的隐含参数,因为运算符重载函数operator+是类的成员函数,所以this指针是该函数的隐含参数。this指针指向对象counter,如果间接引用this指针(*this)则其返回对象counter,对象counter的成员变量m_val已经有正确的值。例15.5 在CCounter重载运算符函数中返回间接引用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的值是:counter.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使用自增运算符+之后,counter的值是:2counter2的值是:3counter的值是:3,程序分析:在上面的程序中,通过间接引用this指针,返回当前对象的引用,并将当前对象的值赋给对象counter2。注意:上面程序中返回的是当前对象的引用,因此就避免了创建多余的临时对象。因为要防止当前的对象值被别的函数改变,所以返回值是const限定的常量引用(回忆一下const限定的使用)。好了,现在类CCounter已经有了一个使用方便,性能卓越的+运算符了。大家自然的会想到前面的+运算符是前缀自增,那后缀自增运算符又该如何重载呢?想的周到,值得表扬。我们下面就看看重载后缀自增运算符如何实现。,(3)重载后缀运算符“+”首先来看看编译器是如何区别前缀自增和后缀自增运算的?按照约定,在运算符重载函数的声明中,提供一个整型数作为函数的参数,就表示重载的是后缀运算符。参数值并没有什么用,它只是用来表明重载的是后缀运算符。在我们重载后缀自增运算符之前,先要彻底搞清楚到底它与前缀自增运算符有什么不同。如果忘记了,请回头去看看前面的C语言部分。前面我们讲到,前缀自增是“先自增,然后再拿来参与运算”,而后缀自增相反,它是“先拿来用,然后变量再自增”。因此,重载前缀运算符只要简单地递增变量的值,然后返回对象本身即可,而后缀运算符必须返回进行自增运算之前的对象的值。为了做到这一点,我们必须创建一个临时对象,用它来存储对象的初始值,然后增加对象的初始值,最后返回临时对象。,让我们通过下面的小例子再简单地回顾一下后缀运算符的使用。m=n+;如果n的值是6,执行完上述语句之后,m的值是6,但是n的值是7。这样,我们返回了变量n原来的值,并且赋给变量m,然后将n的值加1。如果n是一个对象,它的后缀自增运算必须先将对象原来的值(如6)存储到一个临时对象中,然后增加n的值(n的值变为7),最后返回临时对象的值并赋给变量m。注意:因为我们返回的是临时对象,所以必须返回对象的值,而不能是返回引用,这是因为临时对象在函数返回时就超出了它的作用范围,将被销毁,如果返回它的引用,那么这个引用将是一个已经不存在的对象的引用,其后果是不可预料的。,例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 counter;cout counter的值是:counter.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;counter2=counter+;cout counter2的值是:counter2.GetVal()endl;cout counter的值是:counter.GetVal()endl;,输出结果counter的值是:0调用自增函数之后,counter的值是:1使用自增运算符+之后,counter的值是:2counter2的值是:3counter的值是:3counter2的值是:3counter的值是:4,在上面的程序中,分别实现了前缀和后缀运算符的重载。注意,在main()函数中使用后缀+运算符时,并没有在它的后面加一个整型的标志,而是像其它内置数据类型一样的来使用后缀+运算符。前面我们已经强调,在后缀运算符重载函数中带一个整型参数,只是为了表明是后缀运算符,其所带的参数值从不被使用。至此,我们实现了前缀和后缀的+运算符的重载。前缀和后缀的自减运算符-的重载完全类似。你不妨自己在类CCounter中添加进去(不要偷懒呦!)。重载运算符事实上就是在实现一个函数,函数的函数名由关键字operator和要重载的运算符组成。如果运算符重载函数是类的成员函数(如上面的示例程序),那么重载一元运算符的函数不带参数。注意,如果重载的是后缀运算符,如+或-,那么不要忘记带一个整型参数作为标志。例如:const CCounter/后缀-,2.二元运算符重载:重载加运算符“+”前面我们讲述了一元运算符前缀自增和后缀自增的重载,它们只是在一个对象上操作。加法运算符“+”是二元运算符,是对两个对象进行操作。如何对类CCounter实现加运算(+)的重载呢?我们的目标是声明两个CCounter类对象,然后对它们进行加运算,例如:CCounter counter1,counter2,counter3;counter3=counter1+counter2;(1)添加成员函数Add(),实现对象相加的功能实现加法功能的第一种方式是:通过在类CCounter中添加一个成员函数Add(),该函数以一个CCounter类对象作为参数,将对象参数的值和当前对象的值相加,然后返回一个CCounter类对象。例15.7 在CCounter类中添加Add()函数,实现两个CCounter对象相加。,程序清单 C15_07.cpp#include using namespace std;class CCounterpublic:CCounter():m_val(0)CCounter(unsigned initVal):m_val(initVal)CCounter()unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;CCounter Add(const CCounter,main()CCounter counter1(1),counter2(3),counter3;/创建三个CCounter类对象counter3=counter1.Add(counter2);/调用成员函数Add()cout counter1的值是:counter1.GetVal()endl;cout counter2的值是:counter2.GetVal()endl;cout counter3=counter1+ounter2的值是:counter3.GetVal()endl;,输出结果counter1的值是:1counter2的值是:3counter3=counter1+counter2的值是:4,(2)重载加运算符“+”我们实现的Add()函数虽然可以正常工作了,但是使用起来不够简单自然。不说大家可能也会想到,我们实现两个CCounter类对象进行加运算的另外一种方法是重载运算符“+”,使加运算可以写为如下形式:CCounter counter1,counter2,counter3;counter3=counter1+counter2;例15.8 在CCounter类中实现重载运算符“+”。,程序清单 C15_08.cpp/重载运算符+#include using namespace std;class CCounterpublic:CCounter():m_val(0)CCounter(unsigned initVal):m_val(initVal)CCounter()unsigned GetVal()const return m_val;void SetVal(unsigned x)m_val=x;CCounter operator+(const CCounter,main()CCounter counter1(2),counter2(4),counter3;/创建三个CCounter类对象counter3=counter1+counter2;cout counter1的值是:counter1.GetVal()endl;cout counter2的值是:counter2.GetVal()endl;cout counter3=counter1+counter2的值是:counter3.GetVal()endl;,输出结果counter1的值是:2counter2的值是:4counter3=counter1+counter2的值是:6,程序分析:在上面的程序中,重载了加(+)运算符。将加运算符重载函数的声明和实现分别与Add()函数的声明和实现,做个比较,它们几乎是一模一样,只是它们的调用语法不同,使用下面的调用方式(2)显然要比方式(1)简单自然:(1)counter3=counter1.Add(counter2);(2)counter3=counter1+counter2;虽然没有多大的变化,但已经足以使程序易于理解,代码书写也更方便了。注意:重载加运算符的方法同样适用于其它的二元运算符,比如,减(-)操作等等。除了重载二元运算符的函数带有一个参数之外,其它的都和重载一元运算符类似。重载运算符函数的参数是对象的常值引用类型。例如:Counter Counter:operator+(const Counter/重载-运算符在上面的程序中,我们实现了二元运算符“+”的重载,其它二元运算符的重载类似,大家可以尝试对类CCounter重载“-”运算符。,3.重载赋值运算符“=”赋值运算符“=”可以被重载,而且必须被重载为成员函数,其重载格式为:其中A表示类名,source是一个A类型的对象。当用户在一个类中显式地重载了赋值运算符“=”时,称用户定义了类赋值运算。它将一个A类的对象source逐域拷贝(拷贝所有的成员)到赋值号左端的类对象中。如果用户没有为一个类重载赋值运算符,编译程序将生成一个缺省的赋值运算符。赋值运算把源对象的值逐域地拷贝到目标对象中。对许多简单的类,如前面的CCounter类,缺省的赋值函数工作的很好。,A A:operator=(const A source)/复制对象source的所有成员,但是,如果用户定义的类中有指针成员,牵扯到内存的分配问题,那么系统提供的缺省的赋值运算就不能正确工作,用户必须显式地为类定义赋值运算。此问题类似于我们在第13章讲到的拷贝构造函数。拷贝构造函数和赋值运算符都是把一个对象的数据成员拷贝到另一个对象,它们的函数体实现非常类似,但是它们是有区别的。拷贝构造函数是要以一个已存在的对象来创建一个新对象,而赋值运算符则是改变一个已存在的对象的值。我们在前面的部分提到过,如果我们自己不定义拷贝构造函数,那么系统会自动提供一个。同样,如果我们对自己定义的类,不定义赋值运算,那么系统也会提供默认的赋值运算操作(operator=)。无论什么时候你使用对象进行赋值时,这个操作都会被调用。例如:CCat cat1(2,4),cat2(5,7);/其它程序代码cat2=cat1;注:关于CCat类的定义,请看第13章的示例13.2。,在上面这段代码中,创建了两个CCat类对象:cat1和cat2,并且把cat1的成员变量m_age和m_weight分别初始化为2和4,把cat2的成员变量m_age和m_weight分别初始化为5和7。在执行过一些程序代码之后,将对象cat1的值赋给cat2,别看这小小的一个举动,却会引发两个潜在的问题:首先,如果成员m_age是一个指针而不是整型变量,会导致什么情况发生?其次,对象cat2的原有的值会发生什么变化?在第13章我们讨论拷贝构造函数的时候,就提出了关于成员变量如果是指针类型的情况,对于赋值运算有同样的问题。在C+的程序中,浅拷贝(逐域拷贝)不同于深拷贝,前者只是简单地拷贝对象的成员。如果类中有指针成员,那么如果使用浅拷贝将导致两个对象将指向同一块存储空间;而深拷贝不同,它会另外分配一块空间给目标对象的指针变量。,例15.9 在CCat类中定义赋值运算,即重载赋值运算符。程序清单 C15_09.cpp/重载赋值运算符=,重载函数中包括预防自复制的代码#include#include using namespace std;class CCatpublic:CCat();/缺省构造函数int GetAge()const return*m_age;char*GetName()const return m_name;void SetAge(int age)*m_age=age;void SetName(char*name);CCat operator=(const CCat,CCat:CCat()m_age=new int;/给指针分配空间*m_age=5;m_name=new char20;/给Name指针分配空间strcpy(m_name,Mypet);void CCat:SetName(char*name)delete m_name;m_name=new charstrlen(name)+1;strcpy(m_name,name);CCat CCat:operator=(const CCat/返回当前对象,main()CCat cat1;cat1.SetAge(2);cout cat1的年龄是:cat1.GetAge()endl 昵称:cat1.GetName()endl;CCat cat2;cat2.SetName(SunFlower);cout cat2的年龄是:cat2.GetAge()endl 昵称:cat2.GetName()endl;cout n把cat1的值赋给cat2.nn;cat2=cat1;cout cat2的年龄是:cat2.GetAge()endl 昵称:cat1.GetName()endl;,输出结果cat1的年龄是:2 昵称:Mypetcat2的年龄是:5 昵称:SunFlower把cat1的值赋给cat2.cat2的年龄是:2 昵称:Mypet,上面CCat类的定义可能把你都搞糊涂了,我想你肯定不理解为什么要把成员变量声明为如下的形式:int*m_age;char*m_name;没错,这样做是有点让人费解。之所以这样做,目的只是为了说明:当成员变量中有指针时,应该如何重载赋值运算符。我们在赋值运算符的重载函数中,通过语句“if(this=),所导致的一个非常大的问题:存储空间没了。更重要的是,当我们使用引用或者间接的引用指针时这种自赋值的情况很可能发生。,比如:CCat cat2;/其它的程序代码CCat/自赋值这样通过重载赋值运算符,很好地解决了我们上面提到的两个问题,一个是当成员变量是指针的问题,另一个是自赋值的问题。,1.用友元函数重载加法运算符“+”有些时候,用成员函数重载运算符会碰到一些麻烦。例如:例15.10 在复数类CComplex中用成员函数重载运算符“+”。程序清单 C15.10.cpp/用成员函数重载运算符+class CComplexpublic:CComplex()real=0.0;image=0.0;CComplex(double rv)real=rv;image=0.0;CComplex(double rv,double iv)real=rv;image=iv;CComplex operator+(const CComplex,三、用友元函数重载运算符,CComplex CComplex:operator+(const CComplex,在上面的程序段中,语句“c1=c2+16;”可被解释为“c1=c2.operator+(16)”。c2是一个复数类CComplex对象,系统用的是复数类中重载的运算符“+”。所需要的参数应该是CComplex类对象,虽然上述语句中给出的参数是整数16,但是系统可以自动的将16进行类型转换,它通过构造函数“CComplex(double rv)real=rv;image=0.0;”,将整数16变为CComplex类类型常量CComplex(16)。因此上述语句可以正常工作。但是,语句“c1=16+c2;”将被解释为“c1=16.operator+(c2);”。这句不会逃过编译器的考核,因为16不是用户定义的CComplex类对象,在程序的上下文中,编译器并不知道用户重载的运算符“+”的含义,所以只好用系统预定义的“+”运算符的含义进行解释,显然,整数常量16不能与复数对象c2进行加法,所以这个语句不能正常工作。,在上述代码中,我们把“+”运算符作为CComplex类的成员函数进行重载,不具有交换性。这是因为作为成员函数重载的运算符“+”仅能通过实际的对象所调用。如果引起调用的是一个非CComplex类对象的值,比如上面的整型数16,则该成员函数就不知何去何从了。那我们该如何做才能让“+”运算符恢复它的灵活性,具有可交换性呢?C+语言的开发者,当然替我们想得很周到了,提供了“灵丹妙药”来解决此问题了。这就是将运算符重载函数作为友元函数来实现。因为友元函数没有隐含的this指针,所以用友元函数实现运算符重载时,该运算符的操作数都必须在友元函数的参数表中明确声明。修改例15.10的程序,将“+”运算符的重载函数作为类CComplex的友元函数来实现。具体实现代码如下:,例15.11 在CComplex类中使用友元函数重载运算符。程序清单 C15.11.cpp/链表类CLinkList的使用/用友元函数重载运算符+class CComplexpublic:CComplex()real=0.0;image=0.0;CComplex(double rv)real=rv;image=0.0;CComplex(double rv,double iv)real=rv;image=iv;friend CComplex operator+(CComplex c1,CComplex c2);/作为类的友元函数,重载加运算符。CComplex()private:doublereal;/复数的实部doubleimage;/复数的虚部;,CComplex operator+(CComplex c1,CComplex c2)CComplextemp;temp.real=c1.real+c2.real;temp.image=c1.image+c2.image;return temp;main()CComplex c1(1,5),c2(3);c1=c2+16;/正确:被编译器解释为c1=operator+(c2,CComplex(16)c1=16+c2;/正确:被编译器解释为c1=operator+(CComplex(16),c2),这次就不会受编译器的“责难”了,可以顺利地通过编译。那么什么时候使用成员函数实现重载,什么时候又用友元函数实现呢?有些运算符必须用成员函数重载,比如赋值运算符“=”、取下标运算符“”、函数调用运算符“()”以及间接指针运算符“-”。但是有些时候,比如例15.10中的情况,我们只能通过友元函数重载来实现,还有输出运算符“”也只能通过友元函数来重载(原因在讲解例15.12时会说明)。总之,二者选择其一,要视具体情况而定。下面给出作为成员函数或是友元函数来实现运算符重载的不同之处:,1)因为成员函数有隐含的this指针,所以在用成员函数重载运算符时,this指针可以作为一个参数使用。这样,如果重载的运算符是一元运算符,则运算符重载函数不需要参数,因为this指针所指的对象就是运算符的操作数;如果重载的是二元运算符,那么运算符重载函数只需要带一个参数,其中参数表示运算符的右操作数,this指针所指的对象则是运算符的左操作数。形式如下:/成员函数形式,重载一元运算符返回类型 C:operator op()/类C对op的解释/成员函数形式,重载二元运算符 返回类型 C:operator op(C&b)/类C对op的解释其中,C是类名,op是要重载的运算符,b是参数。,2)因为友元函数没有隐含的this指针,所以用友元函数实现运算符重载时,该运算符的操作数都必须在友元函数的参数表中明确声明。如果重载的运算符是一元运算符,则运算符重载函数就要带一个参数,表示操作数;如果重载的是二元运算符,那么运算符重载函数就要带两个参数,分别表示两个操作数。形式如下:/作为类C的友员函数,重载一元运算符返回类型 operator op(C&a)/对op的解释/作为类C的友员函数,重载二元运算符返回类型 operator op(C&

    注意事项

    本文(第12章--运算符重载课件.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开