为什么运算符<应该是非成员函数?
Why should operator< be non-member function?
我记住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)不是,因为zero不是Float
。
您可以看到,在第一种情况下,member function
的代码长度较低,而在第二种情况中,non-member function
使比较更容易。所以我想知道
- 在第一种情况下,我应该使用
member function
而不是non-member function
吗 - 为什么
C++ Primer
建议binary operator
是non-member function
member function
和non-member function
是否有其他不同的情况
谢谢你的帮助!
我认为基本答案是非成员函数在隐式转换中发挥得更好。因此,如果您可以将二进制运算符写成非成员函数,那么您应该这样做。
这个问题可以在不同级别得到回答。从设计的角度来看,在最高级别上,operator<
是一个二进制运算符。这不再是左手边的操作,而是右手边的操作。另一方面,成员函数绑定到第一个参数,它们是对第一个类型的操作。
从技术角度来看,一直到C++语言,这归结为您已经注意到的:成员函数相对于类型是不对称的。这种缺乏对称性意味着声明为成员函数的operator<
只能在左手边是包含该成员的类型的时应用。在调用成员运算符之前,不能应用任何转换。另一方面,由于自由函数与第一个自变量的绑定程度并不比与第二个自变量的约束程度高,因此每当两个自变量中的任何都是适当的类型时,ADL就会提取自由函数operator<
,从而允许对第一个和第二个参数进行相同的转换。
作为非成员,比较运算符也适用于派生类(左侧)参数。
EDIT:正如@jonathan在评论中指出的,它还允许值转换,例如int
左侧参数。
如果构造函数和转换运算符不是explicit
,则这种转换可能允许无意义且可能是无意的代码,例如将T
实例与5进行比较。
- 错误:请求成员 .. 是非类类型"char"
- 请求成员 'begin' in 'c' 中,它是非类类型 'char [101]' sort(c.begin(), c
- 枚举不是非静态数据成员或类的基类
- 请求成员“写入”中的“chol_out_data”,这是非类类型
- C 要求成员''in'',该请求是非类型的“”
- 是非静态数据成员错误的CPPReference定义
- 重载运算符时出错(必须是非静态成员函数)
- 运算符"="必须是非静态成员函数错误
- C++:成员'的错误请求;Foo'在'f',其是非类类型'Foo*'
- 为什么运算符<应该是非成员函数?
- 请求以"y"表示的成员'print',这是非类类型
- C++错误 C2801:'operator ='必须是非静态成员
- 为什么 operator[] 必须是非静态成员函数
- 转换函数可以是非成员函数吗?
- 错误:"Function"不是非静态数据成员或基类 "Class"
- 请求成员“c_str”中的“str”,这是非类的
- 为什么迭代器::end()是非静态成员,与字符串::npos不相似
- 错误:请求成员…在. .它是非类类型的
- 英特尔C++错误:"pair"不是非静态数据成员或类"std::pair<const int, double>"的基类
- 为什么重载复合赋值操作符可以是非成员函数