有两种方法可以为C ++类重载运算符:
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 ;
}
} ;
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#中你只能使用“外部类”方法。)
在C ++中,哪种方式更正确?哪个更好?
答案 0 :(得分:49)
基本问题是“您是否希望在操作员的左侧参数上执行转换?”。如果是,请使用免费功能。如果不是,请使用班级成员。
例如,对于字符串的operator+()
,我们希望执行转换,以便我们可以这样说:
string a = "bar";
string b = "foo" + a;
执行转化以将char * "foo"
变为std::string
。因此,我们将字符串operator+()
变为自由函数。
答案 1 :(得分:16)
首先:两种不同的方式实际上是“作为成员重载”和“作为非成员重载”,而后者有两种不同的方式来编写它(as-friend-inside类定义和外部类定义) 。称他们为“课堂内”和“课堂外”会让你感到困惑。
+ =,+, - =, - 等的重载具有特殊模式:
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参数的其他答案中提到的转换,同时大大简化了实现。 (成员或非成员允许RHS以const&
或按值传递时的转换。)当然,这仅适用于您实际上想要超载+ =和+, - =和 - 等,但这仍然很常见。
此外,您有时希望使用friends在类定义中将非成员op +等声明为Barton-Nackman trick,因为由于模板和重载的怪癖,可能找不到它otherwise
答案 2 :(得分:4)
在Meyer的Effective C ++中对这个问题进行了很好的讨论:第24项是“当类型转换应该应用于所有参数时声明非成员函数”,第46项是“当类型转换是在模板中定义非成员函数时所需的”。