c++ - 后缀运算符重载顺序

标签 c++ operator-overloading post-increment

<分区>

Possible Duplicate:
Undefined Behavior and Sequence Points

重载后缀运算符时,我无法理解操作顺序。让我们来看看下面的两个小例子:

int i = 0;
std::cout << std::endl << "i: " << i;
i = ++i;
std::cout << std::endl << "i: " << i;
i = i++;
std::cout << std::endl << "i: " << i;

MyClass myObject;
std::cout << std::endl << "myObject: " << myObject.getMyValue();
myObject = ++myObject;
std::cout << std::endl << "myObject: " << myObject.getMyValue();
myObject = myObject++;
std::cout << std::endl << "myObject: " << myObject.getMyValue();

出现了两种截然不同的行为。输出结果如下:

i: 0
i: 1
i: 2
myObject: 0
myObject: 1
myObject: 1

不同的行为,你看。这是我的重载运算符方法的概要。

MyClass & MyClass::operator++ ()
{
    ++myValue;
    return *this;
}

MyClass MyClass::operator++ (int postfixFlag)
{
    MyClass myTemp(*this);
    ++myValue;
    return myTemp;
}

好的。前缀是有道理的。你递增任何你需要的,然后返回相同的对象,现在修改,以防赋值。但是后缀让我感到困惑。它应该分配,然后递增。这里我们 self 分配。所以对于内置的整数类型,它是有意义的。我将 i 的值赋给它自己,然后 i 递增。很公平。但是假设 MyClass 是对 int 的重新创建。它从 0 开始,前缀递增,然后变为 1。然后是关键行。 我的对象 = 我的对象++。这与 myObject = myObject.operator++(int postfixFlag) 相同。它被调用。 myTemp 初始化为值 1。它递增到 2。然后我们返回温度。如果我们正在分配给另一个对象,那就行得通了。但是这里我是自赋值的,所以在递增到 2 之后,myObject 被设置为等于返回的用初始值初始化的临时对象,我们又回到了 1!这就说得通了。但这是一种根本不同的行为。

我该如何解决? int 是怎么做到的?这个方法一般是怎么写的?您对与此相关的 C++ 行为和设计有何评论?等等。我现在有点困惑,因为书籍和在线示例似乎总是使用上述方法的变体。

感谢阅读,我们将不胜感激!

最佳答案

正如其他人所说,int 的行为是不确定的。但我想我会尝试解释为什么你的 MyClass 它永远不会达到 2。

诀窍在于您在后缀版本中执行以下三个步骤:

  1. 制作一个名为 myTempthis 拷贝(myValue == 1)。
  2. 递增 this->myValue(所以 myTemp.myValue == 1this->myValue == 2)。
  3. 返回 myTemp(myValue == 1)。

因此您正在修改 this,但是调用 myObject++ 的代码永远不会再看到 this。它只会查看返回的值,它是 old myObject 的拷贝。

operator++ 的代码很好。问题在于您如何使用它——您不应该将预增量或后增量的结果写回同一个变量(行为未定义)。下面是一些可能更有指导意义的代码:

int i = 0;
std::cout << "i: " << i << std::endl;
int j = ++i;
std::cout << "i: " << i << ", j: " << j << std::endl;
int k = i++;
std::cout << "i: " << i << ", k: " << k << std::endl;

MyClass myObject;
std::cout << "myObject: " << myObject.getMyValue() << std::endl;
MyClass myObject1 = ++myObject;
std::cout << "myObject: " << myObject.getMyValue()
    << ", myObject1: " << myObject1.getMyValue() << std::endl;
MyClass myObject2 = myObject++;
std::cout << "myObject: " << myObject.getMyValue()
    << ", myObject2: " << myObject2.getMyValue() << std::endl;

这打印:

i: 0
i: 1, j: 1
i: 2, k: 1
myObject: 0
myObject: 1, myObject1: 1
myObject: 2, myObject2: 1

我更改了您的代码,这样它就不会重新分配给自己,而是每次都分配给一个新变量。请注意,在 intMyClass 两种情况下,主变量 (i/myObject) 都会递增次。但是,在预增量情况下,新变量 (j/myObject1) 具有新值,而在后增量情况下,新变量 (k/myObject2) 采用旧值。

编辑:只是回答问题的另一部分,“int 是如何做到的?”我假设这个问题的意思是“int 类中的预增量和后增量代码是什么样的,我怎样才能使我的相同?”答案是,没有“int 类”。 int 是 C++ 中的一种特殊内置类型,编译器对其进行特殊处理。这些类型不是用普通的 C++ 代码定义的,它们是硬编码到编译器中的。

注意:对于任何想自己尝试的人,这里是问题未包含的 MyClass 的代码:

class MyClass
{
private:
    int myValue;
public:
    MyClass() : myValue(0) {}
    int getMyValue() { return myValue; }
    MyClass& operator++();
    MyClass operator++(int postfixFlag);
};

关于c++ - 后缀运算符重载顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6515656/

相关文章:

c++ - 用在别处创建的对象填充 std::vector

python - Python 3.x 中的 `__rdiv__()` 和 `__idiv__` 运算符是否已更改?

c - 使用 i++(或++i)真的是一个好习惯吗?

c - 该程序的输出。困惑吗?

c++ - 在 C++ 中修改 "Const Char Pointers"

c++ - boost Asio : waiting until thread_group has processed all posted tasks?

c++ - 为什么我不能打印 "first"?

c - “无论如何,遵循 "prefer++i over i++"指南,你就不会出错。” C语言中这背后的原因是什么?

c++ - 为什么 std::pair 的大小与其元素的大小之和不同?

swift - '!=' 运算符的使用不明确