看看这些功能签名:
class Number {
public:
Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
};
前缀不接受任何参数但后缀不起作用。为什么?我认为我们可以用不同的返回类型识别它们。
答案 0 :(得分:10)
前缀和后缀++
是不同的运算符。使用标准Foo operator symbol(Foo &)
样式声明,没有明显的方法来区分这两者。而不是提出一些像Foo symbol operator(Foo &)
这样的新语法,这会使它成为一个特殊情况,不像所有其他运算符,并且可能有点难以解析,语言设计者需要一些其他解决方案。
他们选择的解决方案有些奇怪。他们注意到所有其他'后缀'运算符(即在其中一个操作数之后发生的运算符)实际上是带有两个参数的中缀运算符。例如,普通的+
,/
或>
。在此基础上,语言设计者决定使用随机伪参数是区分前缀和后缀++
的好方法。
由于两个原因,您无法根据返回类型区分它们。
首先,C ++中的函数不能在返回类型上重载。您不能拥有两个具有相同名称和参数类型列表但返回值不同的函数。
第二个方法是,该方法不够健壮或不够灵活,无法处理前缀和后缀++
的所有可能实现。
例如,您可能需要一个返回引用类型的后缀++
,如果您调用它的唯一原因是调用与您应用它的变量值无关的副作用。在我看来,这将是一个非常糟糕的实现,但C ++不是要判断你想要编写什么类型的愚蠢代码,而是要让你能够编写你认为适合于这种情况的任何代码。并且强制您使用一种特定样式的返回类型作为前缀++
和后缀++
将违背这种精神。
答案 1 :(得分:8)
你可以自由地给operator ++任何你喜欢的返回类型,所以没有办法区分postfix和前缀。所以编译器需要某种线索。
OTOH,我不知道为什么这只能用语法来完成:
//prefix
int& ++operator ();
//postfix
int& operator++ ();
毕竟,模仿声明中的用法在C和C ++中具有传统。
P.S。其他海报:这与返回类型的重载无关。后缀和前缀++ / - 是两个不同的名称。无需解决x++
或++x
中的重载问题,因为它的名称完全清楚。
答案 2 :(得分:7)
直接来自Bjarne的嘴巴:
这可能既太可爱又太微妙,但它有效,不需要新的语法,并且具有疯狂的逻辑。其他一元运算符是前缀,在定义为成员函数时不带参数。 “奇数”和未使用的伪
int
参数用于指示奇数后缀运算符。换句话说,在后缀的情况下,++
位于第一个(实际)操作数和第二个(虚拟)参数之间,因此是后缀。这些解释是必要的,因为这种机制是独特的,因此有点疣。如果有选择,我可能会引入
prefix
和postfix
个关键字,但那时似乎不可行。然而,唯一真正重要的一点是该机制可以工作,并且可以被真正需要它的少数程序员理解和使用。
顺便说一句,在我看来,只有前缀++
应该由程序员重载,并且后缀++
应该由编译器自动生成。有人同意我的意见吗?
答案 3 :(得分:2)
不允许纯粹通过返回类型重载函数,因此需要使用虚拟参数来区分两个相同的operator++()
运算符。
答案 4 :(得分:0)
如果我有我的druthers,postincrement和许多序列点操作员将被分成两个或三个部分;在后增量的情况下,语句如“a =(b ++ + c ++);”将被有效地翻译为“a = postinc1(b)+ postinc1(c); postinc2(b); postinc2(c);”;后增量的第二部分是无效函数。在实际实现中,postinc2()调用应该经常发生,而其他一些结果则位于评估堆栈上;这对编译器来说应该不会太难实现。
在“&&”的情况下或“||”,运算符的第一部分只对左操作数进行操作;如果它返回非零(对于&&)或非零(对于||),则第二部分将在两个操作数上运行。
在“?”/“:”的情况下,运算符的第一部分仅对第一个操作数进行操作。如果它返回非零,则第二部分将对第一和第二参数进行操作;否则第三部分将对第一和第三参数进行操作。
是否有任何语言可以做这样的事情?奇怪的是,C ++允许以破坏排序行为的方式重新定义运算符,但不允许以保留它的方式重新定义它们。
答案 5 :(得分:0)
编译器使用int参数来区分前缀和后缀增量运算符。对于隐式调用,默认值为零,因此在重载运算符的功能上没有太大差别......