关于c ++:运算符在类外重载

Operator overloading outside class

本问题已经有最佳答案,请猛点这里访问。

对于C++类有两种重载运算符的方法:

课堂内

1
2
3
4
5
6
7
8
9
10
11
12
13
class Vector2
{
public:
    float x, y ;

    Vector2 operator+( const Vector2 & other )
    {
        Vector2 ans ;
        ans.x = x + other.x ;
        ans.y = y + other.y ;
        return ans ;
    }
} ;

课外

1
2
3
4
5
6
7
8
9
10
11
12
13
class Vector2
{
public:
    float x, y ;
} ;

Vector2 operator+( const Vector2& v1, const Vector2& v2 )
{
    Vector2 ans ;
    ans.x = v1.x + v2.x ;
    ans.y = v1.y + v2.y ;
    return ans ;
}

(显然,在C中,只能使用"outside class"方法。)

在C++中,哪种方式更正确?哪个更好?


基本问题是"是否希望在运算符的左侧参数上执行转换?"。如果是,请使用自由函数。如果不是,请使用类成员。

例如,对于字符串的operator+(),我们希望执行转换,这样我们可以说:

1
2
string a ="bar";
string b ="foo" + a;

在执行转换以将char *"foo"转换为std::string的情况下。所以,我们把字符串的operator+()变成一个自由函数。


第一:这两种不同的方式实际上是"成员超载"和"非成员超载",后者有两种不同的方式来写它(作为类内定义和类外定义的朋友)。称他们为"班内"和"班外"会让你困惑。

+=、+、-=、-等的重载具有特殊模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct Vector2 {
  float x, y;
  Vector2& operator+=(Vector2 const& other) {
    x += other.x;
    y += other.y;
    return *this;
  }
  Vector2& operator-=(Vector2 const& other) {
    x -= other.x;
    y -= other.y;
    return *this;
  }
};
Vector2 operator+(Vector2 a, Vector2 const& b) {
  // note 'a' is passed by value and thus copied
  a += b;
  return a;
}
Vector2 operator-(Vector2 a, Vector2 const& b) { return a -= b; } // compact

此模式允许在对lhs参数的其他答案中提到的转换,同时大大简化了实现。(当以const&或按值传递时,无论是成员还是非成员,都允许对rhs进行转换,因为它应该是这样的。)当然,这只适用于您确实希望同时重载+=和+、-=和-等内容的情况,但这仍然很常见。

此外,有时您希望使用barton-nackman技巧将非成员op+等声明为类定义中的朋友,因为由于模板和重载的奇怪,因此可能不会找到其他的。


在迈耶的有效C++中有一个很好的讨论:项目24是"当类型转换应该适用于所有参数时声明非成员函数",而项目46是"在需要类型转换时定义模板内的非成员函数"。