C++ 中运算符重载的返回值
我对 C++ 中运算符重载的返回值有疑问。一般来说,我发现了两种情况,一种是按值返回,一种是按引用返回。那么这背后的规则是什么呢?特别是在可以连续使用运算符的情况下,例如cout<
例如,当实现+操作“string + (string)”时。如何通过 ref 或 val 返回返回值。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有些运算符按值返回,有些按引用返回。一般来说,结果为新值的运算符(如 +、- 等)必须按值返回新值,而结果为现有值但经过修改的运算符(如 <<、> 等)必须按值返回新值。 >、+=、-= 等),应返回对修改值的引用。
例如,
cout
是一个std::ostream
,向流中插入数据是一个修改操作,所以要实现<<
> 运算符插入到ostream
中,该运算符的定义如下:这样,当您有像
cout << 这样的复合语句时, 该运算符的定义如下: x << y
,子表达式cout <<首先计算 x
,然后计算表达式[result of cout <<; x ] << y
被评估。由于x
上的运算符<<
返回对cout
的引用,因此表达式[result of cout << x ] << y
等价于cout << y
,正如预期的那样。相反,对于“string + string”,结果是一个新字符串(两个原始字符串均未更改),因此它必须按值返回(否则您将返回对临时值的引用,这是未定义的行为)。
Some operators return by value, some by reference. In general, an operator whose result is a new value (such as +, -, etc) must return the new value by value, and an operator whose result is an existing value, but modified (such as <<, >>, +=, -=, etc), should return a reference to the modified value.
For example,
cout
is astd::ostream
, and inserting data into the stream is a modifying operation, so to implement the<<
operator to insert into anostream
, the operator is defined like this:This way, when you have a compound statement like
cout << x << y
, the sub-expressioncout << x
is evaluated first, and then the expression[result of cout << x ] << y
is evaluated. Since the operator<<
onx
returns a reference tocout
, the expression[result of cout << x ] << y
is equivalent tocout << y
, as expected.Conversely, for "string + string", the result is a new string (both original strings are unchanged), so it must return by value (otherwise you would be returning a reference to a temporary, which is undefined behavior).
为了尝试回答有关字符串的问题,字符串的运算符 +() 几乎总是作为自由(非成员)函数实现,以便可以对任一参数执行隐式转换。也就是说,您可以这样说:
鉴于此,并且我们可以看到两个参数都无法更改,因此必须将其声明为:
我们暂时忽略 RETURN_TYPE。由于我们无法返回任何一个参数(因为我们无法更改它们),因此实现必须创建一个新的串联值:
现在,如果我们将 RETURN_TYPE 设为引用,我们将返回对本地对象的引用,这是一个很好的-已知禁忌,因为函数外部不存在本地对象。所以我们唯一的选择就是返回一个值,即一个副本:
To attempt an answer to your question regarding strings, the operator+() for strings is almost always implemented as a free (non-member) function so that implicit conversions can be performed on either parameter. That is so you can say things like:
Given that, and that we can see that neither parameter can be changed, it must be declared as:
We ignore the RETURN_TYPE for the moment. As we cannot return either parameter (because we can't change them), the implementation must create a new, concatenated value:
Now if we make RETURN_TYPE a reference, we will be returning a reference to a local object, which is a well-known no-no as the local object don't exist outside the function. So our only choice is to return a value, i.e. a copy:
如果您希望运算符重载的行为类似于内置运算符,那么规则非常简单;该标准准确定义了内置运算符的行为方式,并将指示内置运算符的结果是
右值
还是左值
。您应该使用的规则是:
rvalue
,那么您的重载应该返回一个引用;lvalue
,那么您的重载应该返回a value但是,您的重载不需要返回与内置相同类型的结果,尽管这是您应该做的,除非您有充分的理由不这样做。
例如,KennyTM 在另一个答案的评论中指出,
<<
和>>
运算符的流重载返回对左操作数的引用,其中不是内置函数的工作方式。但流接口的设计者这样做是为了可以链接流 I/O。If you want your operator overload to behave like the built-in operator, then the rule is pretty simple; the standard defines exactly how the built-in operators behave and will indicate if the result of a built-in is an
rvalue
or anlvalue
.The rule you should use is:
rvalue
then your overload should return a referencelvalue
then your overload should return a valueHowever, your overload isn't required to return the same kind of result as the built-in, though that's what you should do unless you have a good reason to do otherwise.
For example, KennyTM noted in a comment to another answer that the stream overloads for the
<<
and>>
operators return a reference to the left operand, which is not how the built-ins work. But the designers of the stream interface did this so stream I/O could be chained.根据运营商的不同,您可能必须按值返回。
当两者都可以使用时,就像在operator+=中一样,您可以考虑以下内容:
Depending on the operator you may have to return by value.
When both can be used though, like in operator+= you could consider the following:
通常,您在更改其所操作对象的值的操作中按引用返回,例如
=
或+=
。所有其他操作均按值返回。不过,这更多的是经验法则。您可以以任何一种方式设计您的运算符。
Usually you return by reference in an operation that changes the value of the things it's operating on, like
=
or+=
. All other operations are return by value.This is more a rule of thumb, though. You can design your operator either way.