137

我读到声明为成员函数的重载运算符是不对称的,因为它只能有一个参数,而自动传递的另一个参数是this指针。所以没有标准来比较它们。另一方面,声明为 a 的重载运算符friend对称的,因为我们传递了两个相同类型的参数,因此可以比较它们。

我的问题是,当我仍然可以将指针的左值与引用进行比较时,为什么首选朋友?(使用非对称版本的结果与对称版本相同) 为什么 STL 算法只使用对称版本?

4

2 回答 2

167

如果将运算符重载函数定义为成员函数,则编译器会将表达式s1 + s2转换为s1.operator+(s2). 这意味着,运算符重载的成员函数在第一个操作数上被调用。这就是成员函数的工作原理!

但是如果第一个操作数不是一个类怎么办?如果我们想要重载第一个操作数不是类类型的运算符,而不是说double. 所以你不能这样写 10.0 + s2。但是,您可以为表达式编写运算符重载成员函数,例如s1 + 10.0.

为了解决这个排序问题,我们将运算符重载函数定义为friendIF 它需要访问private成员。friend在需要访问私有成员时才设置。否则干脆让它成为非朋友非成员函数来提高封装性!

class Sample
{
 public:
    Sample operator + (const Sample& op2); //works with s1 + s2
    Sample operator + (double op2); //works with s1 + 10.0

   //Make it `friend` only when it needs to access private members. 
   //Otherwise simply make it **non-friend non-member** function.
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

阅读这些:
操作数排序的小问题
非成员函数如何改进封装

于 2011-01-07T04:17:50.497 回答
21

运算符重载和成员函数运算符重载之间不一定有区别,friend因为它是全局运算符重载和成员函数运算符重载之间的区别。

首选全局运算符重载的一个原因是,如果您希望允许类类型出现在二元运算符右侧的表达式。例如:

Foo f = 100;
int x = 10;
cout << x + f;

这仅在存在全局运算符重载时才有效

Foo 运算符 + (int x, const Foo& f);

请注意,全局运算符重载不一定是friend函数。仅当它需要访问 的私有成员时才需要这样做Foo,但情况并非总是如此。

无论如何,如果Foo只有成员函数运算符重载,例如:

class Foo
{
  ...
  Foo operator + (int x);
  ...
};

...那么我们将只能有一个Foo实例出现在加号运算符左侧的表达式。

于 2011-01-07T04:12:25.690 回答