81

我读过一个声明为成员函数的重载运算符是不对称的,因为它只能有一个参数,而另一个自动传递的参数是'this'指针。所以没有标准来比较它们。另一方面,被声明为朋友的重载运算符是对称的,因为我们传递了两个相同类型的参数,因此可以进行比较。 我的问题是,当我仍然可以比较一个指针的左值与引用时,为什么朋友更喜欢? (使用非对称版本会得到与对称版本相同的结果) 为什么STL算法只使用对称版本?运算符重载:成员函数与非成员函数?

+9

你的问题实在是只有约二元运算符。并非所有重载操作符都被限制为单个参数。 ()运算符可以接受任意数量的参数。另一方面,一元运算符不能有任何参数。 – 2011-01-07 04:16:23

+1

http://stackoverflow.com/a/4421729/103167 – 2012-02-19 01:09:23

+2

这是[C++ FAQ:运算符重载]中涵盖的许多主题之一(http://stackoverflow.com/questions/4421706/operator-overloading) – 2012-02-19 01:09:37

回答

101

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

但是如果第一个操作数不是类呢? 如果我们想要在第一个操作数不是类的类型时重载操作符,那么存在一个主要问题,而不是类型double所以你不能这样写10.0 + s2。但是,您可以编写运算符重载成员函数,用于表达式如s1 + 10.0

为了解决这个订购问题,我们定义操作重载功能friend如果需要访问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 
} 

阅读这些:
A slight problem of ordering in operands
How Non-Member Functions Improve Encapsulation

14

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

一个理由,更喜欢一个全球运算符重载是,如果你想允许式,其类类型的二元运算符的右手边出现。例如:

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

这只能如果存在用于

富操作者+(INT X,常量富& F)一个全球运营商超载;

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

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

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

...那么我们只能够在那里一个Foo实例上似乎有表情离开的加运营商。