例子
//全局
friend Complex operator+(const Complex &c1, const Complex &c2);
//成员,记得加=号,“+=”
Complex & operator+=(const Complex &c);
对于全局函数形式的重载“+”
-
先来看
b = a + 1.1
;,实际上会被转换为b = operator+(a, 1.1);
这样的形式进行调用;因为存在转换构造函数,并且第一个参数为 double,那么编译器就会将 1.1 转换为一个匿名 complex 对象complex(1.1),进而在运算符重载函数内部将它们两个的实部,虚部相加,然后返回一个匿名 complex 对象并赋值给 b; -
而对于
b = 2.2 + a
;,也是一样的道理,被转换为b = operator+(2.2, a)
;这样的形式,然后又调用转换构造函数将 2.2 转换为一个匿名 complex 对象complex(2.2),后面的步骤同上;
对于成员函数形式的重载 “+”
- 对于
b = a + 1.1
;,被转换为b = a.operator+(1.1)
;,1.1 也是被转换为complex(1.1); - 对于
b = 2.2 + a
;,被转换为b = (2.2).operator+(a)
;,这很显然是不正确
的,进而编译报错;
为什么以全局函数方式重载运算符 “+”
理由:
以全局函数的形式重载 +,是为了保证 + 运算符的操作数能够被对称的处理
;换句话说,小数(double)在 + 左边和右边都是正确的;
为什么以成员函数方式重载运算符 “+=”,不是“+”
理由:
我们首先要明白,运算符重载的初衷是给类添加新的功能,方便类的运算,它作为类的成员函数是理所应当的,是首选的;不过,类的成员函数不能对称地处理数据,程序员必须在(参与运算的)所有类型的内部都重载当前的运算符;
总结
以上面的情况为例,我们必须在 Complex 和 double 内部都重载 + 运算符,这样做不但会增加运算符重载的数目,还要在许多地方修改代码,这显然不是我们所希望的,所以 C++ 进行了折中,允许以全局函数(友元函数)的形式重载运算符;
-
采用全局函数能使我们定义这样的运算符,它们的参数具有逻辑的对称性;
与此相对应的,把运算符定义为成员函数能够保证在调用时对第一个(最左的)运算对象不出现类型转换,也就是上面提到的「C++ 不会对调用成员函数的对象进行类型转换」; -
有一部分运算符重载既可以是成员函数也可以是全局函数,虽然没有一个必然的、不可抗拒的理由选择成员函数,但我们应该优先考虑成员函数,这样更符合运算符重载的初衷;
-
另外有一部分运算符重载必须是全局函数,这样能保证参数的对称性;
除了 C++ 规定的几个特定的运算符外,暂时还没有发现必须以成员函数的形式重载的运算符
;C++ 规定,箭头运算符->
、下标运算符[]
、函数调用运算符()
、赋值运算符=
只能以成员函数的形式重载;