【发布时间】:2017-10-18 18:29:04
【问题描述】:
考虑:
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).”之类的东西,但我得到的是编译器抱怨一些“不匹配调用 '(Example) (int)'”。
接下来我很好奇“++e”如何神秘地扩展为“e.operator++()”,即返回引用的那个。
玩了一些,我最终得到了:
Example e = 1;
++e++;
e.print();
其中打印了 2,然后:
Example e = 1;
(++e)++;
e.print();
其中打印了 3。
我知道 (++e) 返回一个对对象的引用,该对象随后会加一,所以这是有道理的。我还怀疑“++e++”在这里给了后缀运算符优先级(正如我在另一篇文章中读到的那样),所以这是增加后缀运算符返回的临时变量。这也是有道理的。这让我想知道表达式是怎样的
++++e
++e++++
++++e++
++++e++++
被扩展(它们都编译并运行并获得预期结果)。
真的,内部到底发生了什么,编译器如何知道要调用哪个 operator++(),以及这些表达式是如何扩展的(尤其是在前缀情况下)? “operator++(int)”中占位符变量的作用是什么?
【问题讨论】:
-
占位符的存在只是为了让两个运算符在重载解析期间不同。该参数未指定,必须保持未使用状态。
-
阅读上面的链接,最后你做的所有例子都缺少序列点。
-
要使您的后缀运算符在语义上符合预期,请将其更改为:
Example operator++(int) { return Example(m_i++); } -
重新打开;这里没有未定义的行为,我认为通用的“运算符重载”线程不是这个问题的好答案
-
@CoryKramer 每个函数的进入和退出都有一个序列点(使用 C++11 之前的术语);和重载的运算符是函数
标签: c++ operator-overloading operators prefix postfix-operator