我读到一个声明为成员函数的重载运算符是不对称的,因为它只能有一个参数,而另一个自动传递的参数是this
指针。因此,没有标准可以比较它们。另一方面,声明为a的重载运算符friend
是对称的,因为我们传递了相同类型的两个参数,因此可以对其进行比较。
我的问题是,当我仍然可以将指针的左值与引用进行比较时,为什么首选朋友?(使用非对称版本可获得与对称相同的结果)为什么STL算法仅使用对称版本?
我读到一个声明为成员函数的重载运算符是不对称的,因为它只能有一个参数,而另一个自动传递的参数是this
指针。因此,没有标准可以比较它们。另一方面,声明为a的重载运算符friend
是对称的,因为我们传递了相同类型的两个参数,因此可以对其进行比较。
我的问题是,当我仍然可以将指针的左值与引用进行比较时,为什么首选朋友?(使用非对称版本可获得与对称相同的结果)为什么STL算法仅使用对称版本?
Answers:
如果将运算符重载函数定义为成员函数,则编译器会将类似的表达式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
}
阅读这些:
操作数排序中的一个小问题
非成员函数如何改善封装
friend
仅当它需要访问私有成员时,以及当您不/无聊编写访问器时,才进行此操作,对吗?
a/b
。
friend
是根据操作分配操作员(几乎可以肯定是公共成员)来实施它们。例如,您可以定义T T::operator+=(const T &rhs)
为成员,然后将非成员定义T operator(T lhs, const T &rhs)
为return lhs += rhs;
。非成员函数应在与类相同的名称空间中定义。
全局运算符重载和成员函数运算符重载之间并不一定要区分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
实例出现在加号运算符的左侧。