在 Google C++ Style Guide 中,有一个关于运算符重载的部分有一个奇怪的声明:
重载也有令人惊讶的后果。例如,您不能转发声明重载的类
operator&
。
这似乎不正确,而且我找不到任何导致 GCC 出现问题的代码。有谁知道那句话是指什么?
标准的 5.3.1 有“可以获取不完整类型对象的地址,但如果该对象的完整类型是声明 operator&() 为成员函数的类类型,则行为未定义(并且没有需要诊断)。”
我也不知道这一点,但正如另一位发帖人指出的那样,很容易看出它如何导致编译器生成不正确的代码。
我也没有听说过,但这会给重载之前和之后相同代码的潜在混淆结果:
#include <iostream>
class Foo;
void bar (Foo& foo) {
std::cout << &foo << std::endl;
}
class Foo {
public:
bool operator & () { return true; }
};
void baz (Foo& foo) {
std::cout << &foo << std::endl;
}
int main () {
Foo foo;
bar(foo);
baz(foo);
return 0;
}
输出:
0x7fff092c55df
1
尽管还有其他原因导致您无论如何都不会这样做 - 重载 address-of 不能很好地与 stl 或许多通用代码一起使用。
我认为这种说法并不准确。像其他答案一样,我在这里猜。首先,我假设他们指的是一元 operator& 而不是二元 operator&。那是:
int x = 5;
int* p = &x; // unary &
if (x & 1) // binary &
您可以转发声明您想要的任何类。但是,如果类重载一元运算符&,并且您在指向这些对象之一的指针上调用一元运算符&,您可能会得到不一致的行为(有时您会简单地获取地址,有时您会调用重载方法)。这很容易变成几乎不可能调试的东西。
我很高兴 fizzer 实际上查看了标准,而不仅仅是猜测。
由于能够重载 operator&,boost 库提供了方便的模板 addressof()来处理查找类的真实地址。并不是我建议您重载 operator&,但如果您需要,可以提供帮助。
编辑以考虑评论:
这是一个猜测,但转发声明的主要原因之一是能够声明指向该类的指针。编译器必须在定义之前对类做出假设——例如,指针的大小。
是否可以通过为 T 重载 operator& 来更改 T* 的大小?(编辑:评论员——我认为不是)——但是
重载 operator& 违反了哪些假设——它如何改变类?
这是一种方法。
我可以写:
class A;
void f(A& x) {
A* xPointer = &x;
}
如果 operator&() 被重载比没有重载,这具有新的含义,编译器可能认为它可以为它生成代码,但这是错误的。
措辞不清楚,您当然可以前向声明类 - 但规则显然采取了您“不应该”在类重载的位置operator&
。
类似的规则也出现在其他编码标准中,例如JSF(pdf)规则 159 规定operator&
不应重载。