C++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数
(根据《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: }
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++学习之路—运算符重载(二)运算符重载作为类的成员函数和友元函数的更多相关文章
- C++运算符重载三种形式(成员函数,友元函数,普通函数)详解
首先,介绍三种重载方式: //作为成员函数重载(常见) class Person{ Private: string name; int age; public: Person(const char* ...
- C++运算符重载形式——成员函数or友元函数
运算符重载是C++多态的重要实现手段之一.通过运算符重载对运算符功能进行特殊定制,使其支持特定类型对象的运算,执行特定的功能,增强C++的扩展功能. 运算符重载的我们需要坚持四项基本原则: (1)不可 ...
- 重载运算符:类成员函数or友元函数
类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...
- FastAPI 学习之路(十二)接口几个额外信息和额外数据类型
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- #Java学习之路——基础阶段二(第一篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- #Java学习之路——基础阶段二(第十一篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- #Java学习之路——基础阶段二(第三篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- #Java学习之路——基础阶段二(第十篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- 学习之路三十二:VS调试的简单技巧
这段时间园子里讲了一些关于VS的快捷键以及一些配置技巧,挺好的,大家一起学习,一起进步. 这段时间重点看了一下关于VS调试技巧方面的书,在此记录一下学习的内容吧,主要还是一些比较浅显的知识. 1. 调 ...
随机推荐
- CodeForces 189A 166E 【DP ·水】
非常感谢 Potaty 大大的援助使得我最后A出了这两题DP ================================== 189A : 求切分后的ribbon最多的数目,不过要求切分后只能存 ...
- POJ 1142 质因数分解
只要很朴素的分解就可以了,数据量不大 #include <stdio.h> #include <string.h> #include <stdlib.h> #inc ...
- 用Verilog实现IIC通讯
注意,此代码是错误代码,并不能实现想要的结果. 之所以留着,因为里面的enable 是独立开来的思想值得借鉴.就是控制单元和运算单元分开(我也是借鉴别人的实现思想).具体用verilogHDL实现II ...
- linux chmod权限
Linux chmod 命令 chmod用于改变文件或目录的访问权限.用户用它控制文件或目录的访问权限.该命令有两种用法.一种是包含 字母和操作符表达式的文字设定法:另一种是包含数字的数字设定法. 1 ...
- mong 备份和恢复
[root@hy-mrz01 bin]# ./mongofiles list -h114.55.5.57 -db pics 20160602152850deeabcb1bd2644afa0c3a9a8 ...
- 使用 stvd 编译STM8S 时能看到使用RAM ROM大小的方法
刚刚安装的STVD编译器,编译时候不显示用了多少RAM和ROM?对于此问题.有两个方法:一是看.map文件 还有一种是 添加一个补丁,详细操作例如以下,能够在我的资源里下载对应的文件. http:// ...
- 数论F - Strange Way to Express Integers(不互素的的中国剩余定理)
F - Strange Way to Express Integers Time Limit:1000MS Memory Limit:131072KB 64bit IO Format: ...
- python2.7 串口操作方式 编译 .py为windows可运行exe文件
一 python操作串口 首先下载安装串口模块pyserial . 代码实现: import serial ser = serial.Serial('/dev/ttyUSB2', 115200) pr ...
- BZOJ 1578: [Usaco2009 Feb]Stock Market 股票市场( 背包dp )
我们假设每天买完第二天就卖掉( 不卖出也可以看作是卖出后再买入 ), 这样就是变成了一个完全背包问题了, 股票价格为体积, 第二天的股票价格 - 今天股票价格为价值.... 然后就一天一天dp... ...
- 关于 Swift
摘自:http://numbbbbb.gitbooks.io/-the-swift-programming-language-/chapter1/01_swift.html Swift 是一种新的编程 ...