Effective C++ 第二十四条 Declare non-member functions when type conve
若所有参数皆需类型转换,请为此采用 non-member 函数
考虑一个例子,有理数相乘是分子分母分别相乘,但是有理数也可以和整数相乘,整数转换为有理数比 double 转换为 int 要合理的多。
我们现在为 Rational 设置乘法运算,有两种考率:
设置 class 内置 operator * 重载
设置 non-member 函数
下面先说第一种,重载运算符
这类重载可以完美胜任乘法运算,不会出错。
但是不能胜任混合运算,不满足与整数运算的交换律
这很好理解,C * 2,C 在前,C 是 Rational ,内置有 operator* 且参数为 Rational,此时 2 会被转换为 Rational(2),也符合构造函数构造规则,构造函数有缺省值,Rational(2)其实是 Rational(2,1);但是 2 * C 就无法运算了,因为 2 是 int 型,不是 class ,没有 operator* (Rational&)这样的重载,也就是 int 不能和 Rational 做运算。C * 2 严格来说不算 int 和 Rational 乘法,int 被转换为了 Rational 才可以做运算。也就是说重载运算符不能满足复杂运算要求。而且一旦构造函数是 explicit 修饰,无论是 C*2 还是 2*C 都无法通过编译,都会出错,因为 Rational 必须被显式构造,2 无法被隐式转换为 Rational(2),也就无法进行运算了。
下面考虑第二种,non-member 函数
按照这种方法,无论是 Rational * int 还是 int * Rational 都可以完美通过。
可能有人问这里是否要声明为 friend 函数呢?在这里其实不用,因为这里的实现不需要用到 Rational 的 private 成员变量,可以通过接口来实现。如果函数需要用到 private 成员变量,那么就可以声明为 non-member friend 函数。第二种情况中这种 non-member 的 operator 重载非常值得注意,毕竟许多人的编程一定会加 friend ,其实并不需要。
总结:
如果你需要为某个函数的所有参数(包括被 this 指针所指向的那个隐喻参数)进行类型转换,那么这个函数必须是个 non-member。