我是一名正在学习C++的学生(尤其是运算符重载部分)。在学习期间,我发现以下使用运算符重载的代码没有产生预期的输出。起初,我遇到麻烦的代码是......
#include <iostream>
using namespace std;
class Power {
int kick;
int punch;
public:
Power(int kick = 0, int punch = 0) {
this->kick = kick; this->punch = punch;
}
void show();
Power operator << (int n);
};
void Power::show() {
cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}
Power Power::operator <<(int n) {
kick += n;
punch += n;
return *this;
}
int main() {
Power a(1, 2);
a << 3 << 5 << 6;
a.show();
}
重载运算符
<<
设计用于将整数添加到实例的所有成员变量。我在一行中安装了三次<<
运算符,例如a + 3 + 5 + 6
。我预计输出将是 kick=15,punch=16
,但控制台显示 kick=4,punch=5
作为该代码的结果。似乎只有第一个<<
操作有效,而后面的代码根本不起作用,就像我预期的那样,就像并行连接的数学运算符一样。
我知道建议代码的这种意外行为可以通过将
&
(参考)添加到像 Power& operator << (int n);
这样的运算符重载中来简单地修复,但我无法理解 为什么 这些会产生完全不同的输出。当我使用 Visual Studio 中的调试功能时,自第二次重载操作以来的计算输出并未应用于目标a
,但除了行为之外我找不到更多答案。
正如您所发现的,您需要
&
来返回 this
的引用。
到底发生了什么?
a << 3
创建一个新的
Power
对象,因为您返回 Power
而不是 Power&
.
让我们称这个新对象为
b
。那么接下来发生的事情是:
b << 5
再次,返回类型为
Power
的新对象。让我们称这个为c
。最后这件事发生了:
c << 6
表达式返回
c
和正确的结果,但您没有捕获该值。你可以这样做:
c = a << 3 << 5 << 6;
然后验证
c
是你所期望的:
c.show();
你也可以像这样捕捉
b
(既然是学习,就不要写这样的表达,很隐晦):
c = (b = a << 3) << 5 << 6;
忘记运算符中的
&
是一个常见的错误。或者更确切地说,一些运算符返回一个副本(operator + (...)
)而其他运算符应该返回一个引用(operator += (...)
)并且我们经常复制/粘贴而忘记调整返回值并且它看起来在大多数情况下都有效当你菊花链时,它开始以非常奇怪的方式失败......
Power Power::operator <<(int n) {
这将返回您的
Power
对象的副本。这个新对象将在进一步的<<
操作中被修改。你的意思是在执行更多<<
操作时修改同一个对象三次。
你应该做的:
Power& Power::operator <<(int n) {
...
然后,相同的对象将通过引用返回。