(根据《C++程序设计》(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明)

对运算符重载的函数有两种处理方式:(1)把运算符重载的函数作为类的成员函数;(2)运算符重载的函数不是类的成员函数,在类中把它声明为友元函数。

1    把运算符重载函数作为类的成员函数

在上一篇博客(http://www.cnblogs.com/hust-ghtao/p/3525522.html)中,运算符重载函数 operator + 就是属于这种形式,它是Complex类中的成员函数。下面对这种方式进行分析。

例1:为了便于说明问题,将重载函数的定义重写如下:

   1: Complex Complex :: operator + ( Complex& c2 )

   2: {

   3:     Complex c ;

   4:     c.real = real + c2.real ;

   5:     c.imag = imag + c2.imag ;

   6:     return c ;

   7: }

有人可能会提出这样的疑问:“+”是双目运算符,为什么重载函数只有一个参数呢?实际上,运算符重载函数应当有两个参数,但是,由于重载函数是Complex类中的成员函数,因此有一个参数是隐含的,运算符函数是用this指针隐式的访问类对象的成员。可以看到operator+访问了两个对象中的成员,一个是this指针指向的对象中的成员,一个是形参对象中的成员。
2    把运算符重载函数作为类的友元函数
    运算符重载函数除了可以作为类的成员函数外,还可以是非成员函数。在有关的类中把它声明为友元函数,即友元运算符重载函数。
    例2:将运算符+重载为适用于复数加法,重载函数不作为成员函数,而放在类外,作为Complex类的友元函数。
   1: class Complex

   2: {

   3: public:

   4:     ...

   5:     friend Complex operator + ( Complex& c1 , Complex& c2 ) ;    //重载函数作为友元函数

   6: private:

   7:     double real ;

   8:     double imag ;

   9: };

  10:  

  11: Complex operator + ( Complex& c1 , Complex& c2 )                    //定义运算符+重载函数

  12: {

  13:     Complex c ;

  14:     c.real = c1.real + c2.real ;

  15:     c.imag = c1.imag + c2.imag ;

  16:     return c ;

  17: }

这个程序和把运算符重载函数作为类的成员函数相比,只做了一处改动,就是将运算符重载函数作为类外的普通函数,并在Complex类中声明它为友元函数。可以看到运算符重载函数有两个参数。C++编译系统将程序中的表达式 c1 + c2 解释为operator + ( c1 , c2 )

有的读者可能会产生疑问:为什么把运算符函数作为友元函数?理由很简单,因为运算符函数要访问Complex类对象中的成员。如果运算符函数不是Complex类的友元函数,而是一个普通函数,它是没有权利访问Complex类的私有成员的。

3    将运算符重载函数作为类的成员函数和友元函数的区别

如果将运算符重在为类的成员函数,它可以通过this指针自由地访问本类的数据成员,因此至少可以少写一个函数的参数。但必须要求运算表达式中第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同。因为必须通过类的对象去调用该类的成员函数,而且只有运算符的返回值与该对象同类型,运算结果才有意义。

例如在例1中,将运算符+重载为类的成员函数,则表达式 c1+c2中第一个参数c1是Complex类对象,运算符函数的返回值的类型也是Complex。

当然这种规定也会带来问题,如想将一个复数和一个整数相加,如c1+i,可以运算符+作为成员函数,形式如下:

   1: Complex Complex :: operator + ( int& i )

   2: { 

   3:     return Complex( real+i ,imag ) ;

   4: }

则在表达式必须是 c3 = c2 + i ;而不能写成c3 = i + c2 ;

如果要求程序员时刻记得重载运算符左右的参数类型,显然不是明智的选择。另外如果出于某种考虑,要求运算符左侧的操作数属于C++的标准类型或是一个其他类的对象,则运算符重载函数不能作为成员函数,只能作为非成员函数。如果需要访问类的私有成员,则必须声明为友元函数。

如还是将一个复数和一个整数相加,如c1+i,可以运算符+作为友元函数,形式如下:

在Complex类中声明:

   1: friend Complex operator + ( int& i , Complex& c ) ; //第一个参数可以不是类对象

   2: friend Complex operator + ( Complex& c , int& i ) ;

在类外定义友元函数:

   1: Complex operator + ( int& i , Complex& c )

   2: {

   3:     return Complex( i+c.real , c.imag ) ;

   4: }

   5:  

   6: Complex operator + (  Complex& c , int& i  )

   7: {

   8:     return Complex( i+c.real , c.imag ) ;

   9: }

经过这样的处理之后,表达式 c3 = i + c2 ;和 c3 = c2 + i ; 都是合法的。编译系统会根据表达式的形式选择调用与之匹配的运算符重载函数。当然也可以把一个运算符重载函数作为友元函数,另一个作为成员函数。但不能两个都作为成员函数,原因显然哈。

究竟把运算符重载函数作为类的成员函数好,还是友元函数好?由于友元函数的使用会破坏类的封装,因此,从原则上说,要尽量将运算符函数作为成员函数。但应统筹考虑各方面的因素,以下提供具体原则,仅供参考:

(1)C++规定,赋值运算符“=”、下标运算符“[]”、函数调用运算符“()”、成员运算符“->”必须作为成员函数。

(2)流插入运算符“<<”和刘提取运算符“>>”、类型转换运算符只能作为友元函数。

(3)一般将单目运算符和复合运算符(+=、-=、/=、*=、!=、^=、%=、>>=、<<=)重载为成员函数。

(4)一般将双目运算符重载为友元函数。

C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数的更多相关文章

  1. C++运算符重载三种形式(成员函数,友元函数,普通函数)详解

    首先,介绍三种重载方式: //作为成员函数重载(常见) class Person{ Private: string name; int age; public: Person(const char* ...

  2. C++运算符重载形式——成员函数or友元函数

    运算符重载是C++多态的重要实现手段之一.通过运算符重载对运算符功能进行特殊定制,使其支持特定类型对象的运算,执行特定的功能,增强C++的扩展功能. 运算符重载的我们需要坚持四项基本原则: (1)不可 ...

  3. 重载运算符:类成员函数or友元函数

    类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...

  4. FastAPI 学习之路(十二)接口几个额外信息和额外数据类型

    系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...

  5. #Java学习之路——基础阶段二(第一篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  6. #Java学习之路——基础阶段二(第十一篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  7. #Java学习之路——基础阶段二(第三篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  8. #Java学习之路——基础阶段二(第十篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  9. 学习之路三十二:VS调试的简单技巧

    这段时间园子里讲了一些关于VS的快捷键以及一些配置技巧,挺好的,大家一起学习,一起进步. 这段时间重点看了一下关于VS调试技巧方面的书,在此记录一下学习的内容吧,主要还是一些比较浅显的知识. 1. 调 ...

随机推荐

  1. UIAlertView、UIActionSheet兼容iOS8

    链接地址:http://blog.csdn.net/nextstudio/article/details/39959895?utm_source=tuicool 1.前言 iOS8新增了UIAlert ...

  2. [置顶] PHP调用move_uploaded_file()提示 failed to open stream: Permission denied(Linxux环境,以Ubuntu12.04为例)

    在使用PHP上传文件之后,我们有时候还需要移动到特定的文件夹,这时候就要调用move_uploaded_file()函数,可是会出现如下错误: Warning: move_uploaded_file( ...

  3. YII重点文件

    yii\di\Containeryii\base\Componentyii\base\Objectyii\base\Configurableyii\web\Applicationyii\base\Ap ...

  4. 二维码类库--phpqrcode使用简介

    #载入类文件 include 'phpqrcode.php'; $value = '二维码内容'; $errorCorrectionLevel = 'L';//容错级别 L.M.Q.H $matrix ...

  5. linux(Centos 6.3)学习笔记

    一.系统分区    1,磁盘分区        使用分区编辑器(partition editor)在磁盘上划分几个逻辑部分.碟片一旦划分成          数个分区,不同类的目录与文件可以存储进不同 ...

  6. ZOJ 2794 Just Pour the Water 【矩阵快速幂】

    给你n个杯子,每次有特定的到水规则,倒m次请问最后每个被子里还有多少水 我们很容易发现每次变化的规则相同,那么可以set 一个矩阵存放 然后多次倒水就相当于矩阵相乘,在m 范围达到(1<= M  ...

  7. phpMyAdmin 手动输入数据库服务器IP

    1 在phpMyAdmin安装目录下查找config.inc.php,如没有则拷贝config.sample.inc.php为config.inc.php 2 修改config.inc.php,加入$ ...

  8. c语言指针数组与数组指针

    一.指针数组和数组指针的内存布局初学者总是分不出指针数组与数组指针的区别.其实很好理解:指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定.它是“储存指针的数组”的简称.数 ...

  9. centos安装python gcc sqlite

    终端中输入命令:yum install gcc -y yum install python -y yum install sqlite -y

  10. Python 绝对简明手册

    Python 绝对简明手册 help(函数名)来获取相关信息 另外,自带的文档和google也是不可少的 2. 基本语法2.1. if / elif / else x=int(raw_input(&q ...