5

为什么我要将 C++ operator() 重载为全局而不是成员函数。例如,==运营商。

为什么这样做?例如在 STL 库中。

4

3 回答 3

14

通常的规则是将左侧对象修改为成员的运算符,将返回新对象的二元运算符作为自由函数;后者的主要动机是因为编译器不会将左侧转换为匹配成员;如果您的类支持任何隐式转换,那么所有常用的二元运算符都应该是自由函数,以便相同的转换规则适用
于左侧和右侧,例如:

class Complex
{
public:
    Complex(double r, double i = 0.0);
    bool operator==( Complex const& other ) const;
};

Complex a;
//  ...
if ( a == 1.0 ) // OK
//  ...
if ( 1.0 == a ) // error.

但:

class Complex
{
public:
    Complex(double r, double i = 0.0);
    friend bool operator==( Complex const& lhs, Complex const& rhs ) const;
};

Complex a;
//  ...
if ( a == 1.0 ) // OK
//  ...
if ( 1.0 == a ) // OK

实现这一点的一种优雅方法是根据成员函数定义基本操作——对于类似+or -,这些将是operator+=and operator-=; 为了进行比较,您需要定义任意约定、成员isEqualcompare(根据结果将返回或零<,然后从模板沿以下行继承:==>

template <typename T>
class ArithmeticOperators
{
    friend T operator+( T const& lhs, T const& rhs )
    {
        T result( lhs );
        result += rhs;
        return result;
    }
    //  And so on, for all of the binary operators.
};

class Complex : public ArithmeticOperators<Complex>
{
public:
    //  ...
    Complex& operator+=( Complex const& other );
    //  etc.
};

请注意,使operator <op>= 函数成为自由函数也有一些论据:自由函数将非常量引用作为其第一个参数,因此需要一个左值(如内置函数operator <op>=)。然而,这似乎不是通常的做法,可能是因为operator=必须是成员,并且以operator <op>=同样的方式对待似乎更自然。

于 2011-09-28T08:41:27.000 回答
2

如果我没记错的话, operator =一定是成员函数。关于operator ==,我认为您实际上并不是指全局而是自由函数(STL 没有全局定义运算符)。有几件事需要考虑,一个是与类本身解耦:如果您的操作符可以根据您的类的公共接口来定义,那么您最好以这种方式实现它以保持对实现内部的访问到最低限度。另一个基本优势是可以在您的类型作为第二个操作数的地方实现一个运算符,考虑类型 T 和 U 之间的相等性:

bool operator ==( T const& t, U const& u ){ ... }
bool operator ==( U const& t, T const& u ){ ... }

如果 T 和 U 类型的对象可以同等比较,那么两者t == uu == t都是有效的并且都产生相同的结果是有意义的。如果您将此运算符定义为成员函数,那么一个将在 T 的实现中,另一个在 U 的实现中。现在考虑 U 是您无法控制的第 3 方类型,或者甚至更好的是基本类型,例如int,现在你没有办法提供这样的算子,只能提供它的免费功能版本。

于 2011-09-28T05:29:09.503 回答
0

将成员函数与参数匹配的规则与匹配自由函数的第一个参数的规则不同。我不确定它们到底有什么不同,但由于它们不同,实际上最好将大多数二元运算符实现为自由函数而不是成员函数,以便参数匹配对两个参数对称地操作。

有一个 except for postfix ++,但那是因为它不是真正的二元运算符,并且只有在重载它时才会播放一个,以便有一种区分它和 prefix 的方法++

于 2011-09-28T05:41:03.613 回答