0

我记得C++ Primer告诉我们operator<应该这样做non-member function,而且我总是遵守规则。但现在我想知道原因。

我写了以下代码:

#include <iostream>
using std::cout;
using std::endl;

struct Point1
{
  int x, y;
  Point1(const int a, const int b): x(a), y(b) { }
};
inline bool operator<(const Point1& lhs, const Point1& rhs)
{
  return lhs.x < rhs.x || (lhs.x == rhs.x && lhs.y < rhs.y);
}

struct Point2
{
  int x, y;
  Point2(const int a, const int b): x(a), y(b) { }
  bool operator<(const Point2& rhs)
  {
    return x < rhs.x || (x == rhs.x && y < rhs.y);
  }
};

int main()
{
  Point1 a(1, 2), b(1, 3);
  cout << (a < b) << " " << (b < a) << endl;
  Point2 c(2, 3), d(2, 4);
  cout << (c < d) << " " << (d < c) << endl;
}

在这种情况下,它们似乎没有什么区别,member功能似乎更简单。

但在这种情况下:

#include <iostream>
using std::cout;
using std::endl;

 // Usually I write it for comparing floats
class Float1
{
  long double _value;
public:
  static const long double EPS = 1e-8;
  Float1(const long double value): _value(value) { }
  const long double Get() const { return _value; }
};
inline bool operator<(const Float1& lhs, const Float1& rhs)
{
  return rhs.Get() - lhs.Get() > Float1::EPS;
}
inline bool operator<(const Float1& lhs, const long double rhs)
{
  return rhs - lhs.Get() > Float1::EPS;
}

class Float2
{
  long double _value;
public:
  static const long double EPS = 1e-8;
  Float2(const long double value): _value(value) { }
  const long double Get() const { return _value; }
  bool operator<(const Float2& rhs)
  {
    return rhs._value - _value > Float2::EPS;
  }
  bool operator<(const long double rhs)
  {
    return rhs - _value > Float2::EPS;
  }
};

int main()
{
  Float1 x(3.14);
  Float2 y(2.17);
  long double zero = .0;
  cout << (x < zero) << " " << (zero < x) << endl;
  //cout << (y < zero) << " " << (zero < y) << endl; Compile Error!
}

(x < zero) 和 (zero < x) 都有效!(long double转换为Float?)

但是 (zero < y) 不会,因为零不是 a Float

您会看到,在第一种情况下,member function代码长度更少,而在第二种情况下,non-member function比较更容易。所以我想知道

  • 在第一种情况下,我应该使用member function而不是non-member function
  • 为什么C++ Primer建议binary operators be non-member function
  • 还有其他情况会member function有所作为non-member function吗?

感谢您的帮助!

4

3 回答 3

5

我认为基本答案是非成员函数在隐式转换中表现更好。因此,如果您可以将二元运算符编写为非成员函数,那么您应该这样做。

于 2012-08-21T01:01:03.053 回答
3

这个问题可以在不同的层次上回答。从设计的角度来看,最高级别operator<是二元运算符。它在右侧不再是左侧的操作。另一方面,成员函数绑定到第一个参数,它们是第一种类型的操作。

从技术的角度来看,直接使用 C++ 语言,这归结为您已经注意到的:成员函数在类型方面不是对称的。缺乏对称性意味着operator<声明为成员函数只能在左侧属于包含该成员的类型时应用。在调用成员运算符之前不能应用任何转换。另一方面,因为自由函数与第一个参数的绑定并不比第二个参数更多,所以只要两个参数中的任何operator<一个属于适当的类型,自由函数就会被 ADL 拾取,从而允许对第一个参数进行相同的转换。第一个和第二个参数。

于 2012-08-21T02:19:24.687 回答
2

作为非成员,比较运算符也适用于派生类(左侧)参数。


编辑:正如@jonathan 在评论中指出的那样,它还允许值转换,例如int左侧参数。

如果构造函数和转换运算符 not explicit,则此类转换可能允许无意义且可能是非预期代码,例如将T实例与 5 进行比较。

于 2012-08-21T01:01:27.607 回答