问题四 这个四则运算符
必须重载为类的成员函数吗
不 重载为类的成员函数是可以的
但实际上
你还可以把它重载为类的友元函数
甚至就是一个普通的函数 没问题
它跟类没关系的一个普通函数也没问题
可以重载为类的友元函数
也可以重载为一个普通的函数
但是你要注意
如果你把它重载为一个普通的函数
那么这个普通函数
它没有权利访问类的私有成员
所以我们建议
将这些四则运算符重载为类的友元函数
实际上你把它重载为类的友元函数
要好过把它重载为类的成员函数
有什么优势呢 重载为类的友元函数的话
它的优势在于：
第一 友元函数中将具有显式的双操作数
因为没有this指针
所以两个操作数（左操作数和右操作数）
你都要作为函数参数传进去
它有显式的双操作数
格式是一致的
重载为类的成员函数的时候
一个左操作数是通过this指针传进去的
右操作数是通过对一个constCouple类的
一个引用传进去的
所以一个是指针 一个是引用
两个操作数的访问格式
实际上是不一样的
它不一致 有点不太美观
写的时候也要注意
所以真编程的时候
实际上有一点点别扭
那么重载为类的友元函数
又不存在这个问题
因为没有this指针了嘛
所以双操作数都是以引用的形式传进去
那么在这种情况下
双操作数的使用格式其实是一致的
还有一个地方
最重要的它不要求我们的左操作数
必须是本类的一个对象
如果你重载为一个类的成员函数 左操作数
它就固定为this所指向的这个本类对象
那如果你重载为类的友元
它不要求这一点
当然 重载为类的友元函数
它也有自己的缺点
缺点就是什么呢
还是一样 显式具有双操作数
你编程的时候就要传双参数
它比单参数传递 接口是麻烦的
所以这个左操作数你是不能够省略的
除了这一点
友元函数其实好过我们的成员函数
我们来看重载之后的这个Couple类的定义
重载的这4个操作符：
operator+、operator*、operator*、operator* 4个
都是重载为类的友元friend
重载为类的友元函数
然后传的都是双参数
你注意我们的标量乘法
我们标量乘法operator*重载了两个版本
一个左操作数是constCouple类的一个引用
一个左操作数是constint的一个引用
为什么要重载两个版本呢
因为重载的这个操作符
它并不天然地支持我们的乘法交换律
所以你必须针对于左操作数
不同的类型重载不同的版本
这是要特别注意的一个地方
关于这个数偶倍乘的运算
有一点需要说明的地方就是 第一
你最好把它重载为类的友元函数
如果不重载为类的友元函数
那左操作数是那个整数的时候
它就没有办法去计算
重载为类的成员函数
左操作数必须个Couple类的一个对象
this指针所指向的那个对象
那么如果它是k乘上Couple类的一个对象
那你怎么去处理 k是一个整数
在k上面调用operator*吗
没有啊 我们没实现呢 这是不能做的
如果非友元函数 当倍数为左操作数时
无法解析我们的乘法运算
第二 左右操作数本身
实际上是不可互换的
重载这个函数你就必须提供两个版本
两个你都得要写
它们的函数签名本身是不一致的
所以不是天然地满足我们的交换律
特别注意这一条
那我们看看 重载为类友元函数以后
内部的实现和前面那个实现
版本其实差不多 本质上是一样的
只是书写的格式有点差异
看看我们的使用
现在有了重载为友元函数的标量的乘法
我们就可以写c= k*c
k是一个整数对象
c是我们Couple类的一个对象
两者相乘 它就会调用我们的友元函数
传第一个参数k 传第二个参数c=
而不是调用我们的成员函数
如果不是重载为友元
那么她试图调用k.operator*(c)
那能调用到吗 调用不到的
如果编译器想调用成功
它就必须把k转型成我们的Couple
这个转型因为我们没有在前面写
它的转型操作 所以它是隐式的
由编译器给我们自动进行
但是这个自动进行
当你把那个单参数构造函数
写成一个explicit的时候
这个自动进行就不允许了
就禁止它这么做了
如果你禁止 它就转型不成功了嘛
如果你没禁止
但它有时候也不一定就能成功
你比如没这个构造函数
它也不成功 对吧
碰到这个情况 那这个编译器就会报错
所以你重载为友元
这个函数只要提供了 其实就没问题了
2*d其实也一样