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. 调 ...
随机推荐
- BZOJ 1096: [ZJOI2007]仓库建设( dp + 斜率优化 )
dp(v) = min(dp(p)+cost(p,v))+C(v) 设sum(v) = ∑pi(1≤i≤v), cnt(v) = ∑pi*xi(1≤i≤v), 则cost(p,v) = x(v)*(s ...
- javascript 学习随笔6
改变html内容 document.getElementById("p1").innerHTML="New text!"; var element=docume ...
- Week5(10月10日):国庆之后,让我们整装期待元旦吧
Part I:提问 =========================== 1.要将“Hello, Admin",从控制器传递到视图,该如何操作? (1)使用ViewData (2)使用V ...
- Best Component for Bitmap Image
The best is to purchase ImageEn and use the latest version. Coz nothing compares to ImageEn.... But ...
- perl 安装 ZooKeeper模块
1072 ./configure --libdir=/usr/lib 1073 make 1074 make install 1075 cpan ZooKeeper [root@wx03 c]# pe ...
- LTP介绍
1.LTP介绍 LTP--linut test project ,ltp套件是由Linux Test Project所开发的一套系统測试套件.它基于系统资源的利用率统计开发了一个測试的组合,为系 ...
- 嵌入式MCU开发群资源
STM32CubeMX是一款图形化软件设置工具,允许使用图形化向导来生成C初始化代码.它是未来开发stm32系列产品的主流软件,是ST公司的主动原创,可以减轻开发工作,时间和费用.STM32Cube ...
- iOS开发网络数据之AFNetworking使用1
链接地址:http://blog.csdn.net/daiyelang/article/details/38421341 如何选择AFNetworking版本 官网下载2.5版本:http://afn ...
- BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )
子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 -------------------------------------------------------------- ...
- Eclipse使用技巧总结(三)
十六.快速关闭窗口 关闭当前打开窗口 Ctrl + W 关闭当前打开的所有窗口 Ctrl +Shift +F4 十九.重命名 F2 二十.快速回到上次编辑点 Ctrl + Q 二十 ...