为什么重载复合赋值运算符可以是非成员函数?

时间:2015-05-16 16:45:57

标签: c++

我刚刚发现复合赋值运算符(例如operator+=operator-=)可以在类范围之外重载。

考虑:

class X { }; // A third party class

// The following function is legal:
X& operator+=(X& lhs, const X& rhs) {
    // ...
}

显然,非成员函数不能触及X的私有接口,因此这里没有封装问题。但它确实使它看起来好像它是X自己界面的一部分,显然它不是。

在我看来,这可能导致一些严重的代码滥用和混乱的行为。想象一下,有人认为将它用于标准包含的一些“聪明的黑客”会很好,例如std::vectorstd::map

这是特别奇怪的,因为operator[]operator->之类的其他运算符不能成为我认为的非成员函数。

那为什么允许呢?

3 个答案:

答案 0 :(得分:4)

  

那为什么允许呢?

您要求我们阅读Stroustrop的思想。不可能。
但是C ++的一般原则并不是限制开发人员(我们不提供一套可以安全使用的绝对工具。我们提供全套剃刀锯和旋转连枷)。

  

在我看来,这可能导致一些严重的代码滥用和混乱的行为。想象一下,有人认为将它用于标准包含的一些“聪明的黑客”会更好,例如std :: vector或std :: map。

是的,它可以 当你滥用运算符重载时,它可能导致一些危险和致命的事情。最好不要这样做(特别是对于其他人或标准类)。

但它可以提供一些潜在有用的情况(当你小心的时候)。这在构建数字“类型”类时特别有用,因为它有助于自动转换,使代码更自然易读。

答案 1 :(得分:3)

考虑库A是否定义了一个对象(比如说一个Matrix对象)。库B扩展了库A,其中包含一些类似的对象(比如矢量)。

库B想要定义将矩阵链接到向量的运算符(例如,乘法)。但是如果定义这些运算符重载必须在原始对象中完成,则编写器将被卡住,并且用户将处于奇怪的情况,他们可以执行向量*矩阵,但不能使用矩阵*向量。

如你所述,特别注意+ =和 - =,考虑一个1乘n的矩阵,它本质上是一个向量。我们现在希望能够执行矩阵+ =向量。

允许在外部定义它们可以避免此问题。

  

在我看来,这可能导致一些严重的代码滥用和混乱的行为

非常正确。但是不要忘记这是一种内置预处理器的语言。如果其他开发人员想让您感到困惑,他们已经拥有了更强大的工具。

答案 2 :(得分:0)

嗯,一个原因是它们可能并不总是适用于类。例如,一组类型安全的标志可能被实现为带有重载运算符的 enum,包括复合赋值运算符:

enum Flags : unsigned {
    None   = 0   ,
    Hot    = 1<<0,
    Crazy  = 1<<1,
    Single = 1<<2
};

constexpr Flags operator | (Flags L, Flags R) {
    return (Flags)((unsigned)L | (unsigned)R);
}

// there's nothing this can be a member *of*.
Flags & operator |= (Flags &L, Flags R) {
    return (L = L | R);
}

// etc...