运算符重载:成员函数与非成员函数?

bad*_*ash 107 c++ operator-overloading member-functions friend-function non-member-functions

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

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

Naw*_*waz 137

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

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

为了解决这个排序问题,我们将运算符重载函数定义为friend需要访问private成员的IF .让它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
}
Run Code Online (Sandbox Code Playgroud)

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

  • @matthias,并非所有运算符都是可交换的.简单的例子是`a/b`. (6认同)
  • @Abhi:选择你的选择:改进封装与懒惰的写作习惯! (4认同)
  • 避免使非成员运营商需要"朋友"的常用方法是在操作赋值运算符(几乎肯定是公共成员)方面实现它们.例如,您可以将`TT :: operator + =(const T&rhs)`定义为成员,然后将非成员`T运算符(T lhs,const T&rhs)`定义为`return lhs + = rhs;`.应该在与该类相同的命名空间中定义非成员函数. (3认同)
  • "只有当它需要访问私人成员时,才能成为'朋友'.当你没有/无聊写入访问者时,对吧? (2认同)
  • @ricky:但是如果lhs是副本(就像在我的评论中那样),那么lhs改变的事实并不重要. (2认同)

Cha*_*via 19

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

偏好全局运算符重载的一个原因是,如果要允许类型出现在二元运算符右侧的表达式.例如:

Foo f = 100;
int x = 10;
cout << x + f;
Run Code Online (Sandbox Code Playgroud)

这仅适用于全局运算符重载的情况

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

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

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

class Foo
{
  ...
  Foo operator + (int x);
  ...
};
Run Code Online (Sandbox Code Playgroud)

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

  • +1用于区分成员函数和非成员函数,而不是成员和朋友函数.我想今天我们会说"全局或命名空间范围". (3认同)