我刚刚发现复合赋值运算符(例如operator+=
或operator-=
)可以在类范围之外重载。
考虑:
class X { }; // A third party class
// The following function is legal:
X& operator+=(X& lhs, const X& rhs) {
// ...
}
显然,非成员函数不能触及X
的私有接口,因此这里没有封装问题。但它确实使它看起来好像它是X
自己界面的一部分,显然它不是。
在我看来,这可能导致一些严重的代码滥用和混乱的行为。想象一下,有人认为将它用于标准包含的一些“聪明的黑客”会很好,例如std::vector
或std::map
。
这是特别奇怪的,因为operator[]
和operator->
之类的其他运算符不能成为我认为的非成员函数。
那为什么允许呢?
答案 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...