代码之家  ›  专栏  ›  技术社区  ›  Naruto

为什么postfix increment运算符采用一个伪参数?

  •  19
  • Naruto  · 技术社区  · 15 年前

    看看这些函数签名:

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

    Prefix不接受任何参数,但postfix接受。为什么?我想我们可以识别出他们有不同的回报类型。

    6 回复  |  直到 12 年前
        1
  •  11
  •   Omnifarious    7 年前

    前缀和后缀 ++ 是不同的操作员。以标准 Foo operator symbol(Foo &) 风格声明没有明显的方法来区分两者。而不是想出一些新的语法 Foo symbol operator(Foo &) 这将使它成为一个不同于所有其他操作符的特殊情况,并且可能有点难以解析,语言设计者想要一些其他的解决方案。

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

    嗯,这是C++演进的一个奇怪的决定。但你已经拿到了。

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

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

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

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

        2
  •  10
  •   Nordic Mainframe    15 年前

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

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

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

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

    P、 这与按返回类型重载无关。后缀和前缀是两个不同的名称。没有必要解决 x++ ++x ,因为它完全清楚哪个名字的意思。

        3
  •  7
  •   fredoverflow    15 年前

    直接从比亚恩嘴里说:

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

    这些解释是必要的,因为机制是独特的,因此有点疣。如果有选择,我可能会介绍 prefix postfix 关键词,但当时看来并不可行。然而,唯一真正重要的一点是,该机制是有效的,并且可以被少数真正需要它的程序员理解和使用。

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

        4
  •  2
  •   AshleysBrain    15 年前

    不允许纯按返回类型重载函数,因此必须使用伪参数来区分两个相同的外观 operator++() 操作员。

        5
  •  0
  •   supercat    15 年前

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

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

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

    有哪种语言能做到这一点吗?奇怪的是,C++允许操作员以中断序列行为的方式重新定义,但不允许它们以保存它的方式重新定义。

        6
  •  0
  •   user2919348    12 年前

    编译器使用int参数来区分前缀和后缀增量运算符。对于隐式调用,默认值是零,因此实际上它不会对重载运算符的功能产生太大的影响。。。

    推荐文章