繁体   English   中英

C++ 编译器如何扩展前缀和后缀运算符 ++()?

[英]How does a C++ compiler expand prefix and postfix operator++()?

考虑:

class Example
{
private:
    int m_i;

public:
    Example(int i) : m_i{i} {}

    //Post-fix
    Example operator++(int) {m_i++; return *this;}

    //Pre-fix
    Example& operator++() {m_i++; return *this;}

    void print() const {std::cout << m_i << '\n'}
};

我正在试验这个以确定编译器如何扩展对前缀和后缀运算符的调用。

例如,当我写这样的东西时:

Example e = 1;
e++;

我预计它会扩展到“e.operator++(int)”之类的东西,或者更进一步,我预计

e++(2);

扩展为“e.operator++(2)”之类的东西,但我得到的是编译器抱怨一些“不匹配调用'(示例)(int)'”。

接下来我很好奇“++e”如何神秘地扩展为“e.operator++()”,即返回引用的那个。

玩了更多,我最终得到:

Example e = 1;
++e++;
e.print();

其中打印了 2,然后:

Example e = 1;
(++e)++;
e.print();

其中打印了 3。

我知道 (++e) 返回对对象的引用,然后将其后递增 1,所以这是有道理的。 我还怀疑“++e++”在这里给出了后缀运算符的优先级(正如我在另一篇文章中读到的),所以这是增加后缀运算符返回的临时变量。 这也有道理。 这让我想知道表达式是如何

++++e
++e++++
++++e++
++++e++++

被扩展(它们都以预期的结果编译和运行)。

所以真的,内部到底发生了什么,编译器如何知道要调用哪个 operator++() ,以及这些表达式是如何扩展的(尤其是在前缀情况下)? “operator++(int)”中占位符变量的用途是什么?

“operator++(int)”中占位符变量的用途是什么?

因为++运算符有两个不同的功能:postfix-++ 和 prefix-++。 因此,在重载它时,必须有两个不同的函数签名。

编译器如何知道调用哪个 operator++(),

当您的代码使用前缀++ (例如: ++e; )时,将调用带有签名operator++()的函数。 当您的代码使用 postfix- ++ (例如: e++ ;) 时,会调用带有签名operator++(int)的函数,并且编译器将提供一个未指定的虚拟参数值。

从技术上讲, operator++(int)可以使用虚拟参数值。 你可以通过编写e.operator++(5);来传递你自己的值e.operator++(5); 而不是e++; . 但这会被认为是糟糕的编码风格——当重载运算符时,建议保留内置运算符的语义以避免混淆阅读代码的人。

请注意,您当前的 postfix- ++实现不遵守此规则:正常语义是应返回先前的值; 但您的代码返回更新后的值。

++e++++;

要解析此语句,您需要了解以下解析规则:

  • 令牌由“最大咀嚼”解析,即这意味着++ e ++ ++; (而不是一些一元- +运算符)。
  • 语言语法根据这些标记确定哪些表达式是哪些运算符的操作数。 这个过程可以总结在一个 优先表中

查阅该表达式的表格会告诉您: ++(((e++)++)) 使用我之前提到的扩展,这可以写成函数调用符号:

((e.operator++(0)).operator++(0)).operator++();

在这种情况下,需要从左到右调用这些函数,因为在对调用它的表达式求值之前无法输入成员函数。

所以,假设我们有Example e(1); 在此语句之前,以下函数调用按此顺序发生:

  • e.operator++(int) - 将e.m_i设置为2并返回一个临时的(我将其称为temp1作为伪代码),其中temp1.m_i2
  • temp1.operator++(int) - 将temp1.m_i设置为3 ,并返回mi3 temp2
  • temp2.operator++() - 将temp2.m_i设置为4并返回对temp2的引用。

注意。 我的回答只谈到重载运算符是一个成员函数。 也可以将++ (两种形式)重载为非成员。 在这种情况下,行为将与我的描述保持一致,但“以函数调用表示法编写”表达式将采用不同的语法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM