为什么后缀增量运算符采用伪参数?

时间:2010-08-26 11:58:52

标签: c++ operator-overloading language-design prefix postfix-operator

看看这些功能签名:

 class Number {
 public:
   Number& operator++ ();    // prefix ++
   Number  operator++ (int); // postfix ++
 }; 

前缀不接受任何参数但后缀不起作用。为什么?我认为我们可以用不同的返回类型识别它们。

6 个答案:

答案 0 :(得分:10)

前缀和后缀++是不同的运算符。使用标准Foo operator symbol(Foo &)样式声明,没有明显的方法来区分这两者。而不是提出一些像Foo symbol operator(Foo &)这样的新语法,这会使它成为一个特殊情况,不像所有其他运算符,并且可能有点难以解析,语言设计者需要一些其他解决方案。

他们选择的解决方案有些奇怪。他们注意到所有其他'后缀'运算符(即在其中一个操作数之后发生的运算符)实际上是带有两个参数的中缀运算符。例如,普通的+/>。在此基础上,语言设计者决定使用随机伪参数是区分前缀和后缀++的好方法。

恕我直言,这是随着C ++的发展而做出的陌生人决定之一。但是你有它。

由于两个原因,您无法根据返回类型区分它们。

首先,C ++中的函数不能在返回类型上重载。您不能拥有两个具有相同名称和参数类型列表但返回值不同的函数。

第二个方法是,该方法不够健壮或不够灵活,无法处理前缀和后缀++的所有可能实现。

例如,您可能需要一个返回引用类型的后缀++,如果您调用它的唯一原因是调用与您应用它的变量值无关的副作用。在我看来,这将是一个非常糟糕的实现,但C ++不是要判断你想要编写什么类型的愚蠢代码,而是要让你能够编写你认为适合于这种情况的任何代码。并且强制您使用一种特定样式的返回类型作为前缀++和后缀++将违背这种精神。

答案 1 :(得分:8)

你可以自由地给operator ++任何你喜欢的返回类型,所以没有办法区分postfix和前缀。所以编译器需要某种线索。

OTOH,我不知道为什么这只能用语法来完成:

//prefix
int& ++operator (); 
//postfix
int& operator++ (); 

毕竟,模仿声明中的用法在C和C ++中具有传统。

P.S。其他海报:这与返回类型的重载无关。后缀和前缀++ / - 是两个不同的名称。无需解决x++++x中的重载问题,因为它的名称完全清楚。

答案 2 :(得分:7)

直接来自Bjarne的嘴巴:

  

这可能既太可爱又太微妙,但它有效,不需要新的语法,并且具有疯狂的逻辑。其他一元运算符是前缀,在定义为成员函数时不带参数。 “奇数”和未使用的伪int参数用于指示奇数后缀运算符。换句话说,在后缀的情况下,++位于第一个(实际)操作数和第二个(虚拟)参数之间,因此是后缀。

     

这些解释是必要的,因为这种机制是独特的,因此有点疣。如果有选择,我可能会引入prefixpostfix个关键字,但那时似乎不可行。然而,唯一真正重要的一点是该机制可以工作,并且可以被真正需要它的少数程序员理解和使用。

顺便说一句,在我看来,只有前缀++应该由程序员重载,并且后缀++应该由编译器自动生成。有人同意我的意见吗?

答案 3 :(得分:2)

不允许纯粹通过返回类型重载函数,因此需要使用虚拟参数来区分两个相同的operator++()运算符。

答案 4 :(得分:0)

如果我有我的druthers,postincrement和许多序列点操作员将被分成两个或三个部分;在后增量的情况下,语句如“a =(b ++ + c ++);”将被有效地翻译为“a = postinc1(b)+ postinc1(c); postinc2(b); postinc2(c);”;后增量的第二部分是无效函数。在实际实现中,postinc2()调用应该经常发生,而其他一些结果则位于评估堆栈上;这对编译器来说应该不会太难实现。

在“&&”的情况下或“||”,运算符的第一部分只对左操作数进行操作;如果它返回非零(对于&&)或非零(对于||),则第二部分将在两个操作数上运行。

在“?”/“:”的情况下,运算符的第一部分仅对第一个操作数进行操作。如果它返回非零,则第二部分将对第一和第二参数进行操作;否则第三部分将对第一和第三参数进行操作。

是否有任何语言可以做这样的事情?奇怪的是,C ++允许以破坏排序行为的方式重新定义运算符,但不允许以保留它的方式重新定义它们。

答案 5 :(得分:0)

编译器使用int参数来区分前缀和后缀增量运算符。对于隐式调用,默认值为零,因此在重载运算符的功能上没有太大差别......