C++ 后缀运算符重载顺序
可能重复:C++ 后缀运算符重载顺序,c++,operator-overloading,post-increment,C++,Operator Overloading,Post Increment,可能重复: 重载后缀运算符时,我无法理解操作顺序。让我们来看看下面的两个小例子: 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 my
重载后缀运算符时,我无法理解操作顺序。让我们来看看下面的两个小例子:
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();
不同的行为,你看。下面是我的重载运算符方法的概要
MyClass & MyClass::operator++ ()
{
++myValue;
return *this;
}
MyClass MyClass::operator++ (int postfixFlag)
{
MyClass myTemp(*this);
++myValue;
return myTemp;
}
好的。前缀有意义。您可以增加所需的量,然后返回相同的对象,在赋值的情况下,该对象现在已修改。但是后缀让我很困惑。它应该赋值,然后递增。这里是自我分配。因此,对于内置的整数类型,它是有意义的。我将I
的值赋给它自己,然后I
会递增。很公平。但是让我们假设MyClass
是int的一种再创造。它从0开始,前缀递增,变成1。然后,关键线路<代码>myObject=myObject++。这与myObject=myObject.operator++(intpostfixflag)
是一样的。有人叫它myTemp
使用值1初始化。它增加到2。然后我们返回温度。如果我们分配给另一个对象,这是可行的。但是这里我是自赋值的,所以在递增到2之后,myObject
被设置为等于返回的用初始值初始化的temp对象,我们回到1!这是有道理的。但这是一种根本不同的行为
我如何解决这个问题?int是如何做到的?这个方法通常是如何编写的?你对C++的行为和设计有什么意见吗?我现在有点困惑,因为书籍和在线示例似乎总是使用上述方法的变体
感谢阅读,如有任何意见,将不胜感激 正如其他人所说,对于int,行为是未定义的。但我想我应该试着解释一下,为什么你们班的成绩永远达不到2分 诀窍在于,在后缀版本中,您将执行以下三个步骤:
myTemp
(其中myValue==1
)的副本
this->myValue
(因此myTemp.myValue==1
;this->myValue==2
)myTemp
(带myValue==1
)此
,但是调用myObject++
的代码将永远不会再看到此
。它只查看返回的值,它是旧的myObject
的副本
运算符++的代码很好。问题在于如何使用它——不应该将增量前或增量后的结果写回同一个变量(行为未定义)。下面是一些可能更具指导意义的代码:
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;
我更改了您的代码,这样它每次都会分配给一个新的变量,而不是重新分配给自身。注意,在int
和MyClass
两种情况下,主变量(i
/myObject
)都是递增的。但是,在增量前的情况下,新变量(j
/myObject1
)采用新值,而在增量后的情况下,新变量(k
/myObject2
)采用旧值
Edit:回答问题的另一部分,“int是如何实现的?”我假设这个问题的意思是“在int
类中,增量前和增量后的代码是什么样子,我如何使我的代码相同?”答案是,没有“int
类”<代码> int /COD>是C++中的一种特殊内置类型,编译器特别对待它。这些类型不是用普通C++代码定义的,它们是硬编译到编译器中的。
注意:对于任何想亲自尝试的人,以下是问题未包括的MyClass
代码:
class MyClass
{
private:
int myValue;
public:
MyClass() : myValue(0) {}
int getMyValue() { return myValue; }
MyClass& operator++();
MyClass operator++(int postfixFlag);
};
i=i++
和i=++i`都表现出未定义的行为。您的int
行为未定义。。。您可以使用不同的编译器、版本、优化级别、目标CPU获得不同的结果,或者根本没有明显的原因。。。你需要对序列点做一些背景阅读。。。这里有很多关于S.O.的问题。甚至还有一个问题。为什么投票结果接近?当然,还有另外一个FAQ解释了一般的序列点,这是一个很好的背景阅读,但它不是这个问题的“完全重复”。事实上,我认为仅仅通过阅读一篇关于序列点的普通讲座就很难找到这个问题的答案。希望我的回答足够了。在这个问题上我是+1。我绝对认为它应该有自己的页面。信不信由你,我在发布前搜索过。你们称之为完全重复,但它只在知道序列点的情况下重复其他问题。我的问题没有提到它们,因为在我写的所有书中,没有一本讨论过它们。我找不到任何关于我的问题的问题,也没有关于未定义行为或序列点的先验知识。因此,我坚持这一点,反对结束这一进程。记住,一个有经验的概念对于新手来说可能是闻所未闻的。感谢您提供的链接,它们提供了信息。+1来自我,因为我们不知何故忽略了myObject
的案例,我们只是跳过了未定义的行为。:)对不起,我的回答太晚了,我已经出国了。欣赏细节
i: 0
i: 1, j: 1
i: 2, k: 1
myObject: 0
myObject: 1, myObject1: 1
myObject: 2, myObject2: 1
class MyClass
{
private:
int myValue;
public:
MyClass() : myValue(0) {}
int getMyValue() { return myValue; }
MyClass& operator++();
MyClass operator++(int postfixFlag);
};