我对C ++中运算符重载的返回值有疑问。通常,我发现了两种情况,一种是按值返回,一种是按引用返回。那么这个规则是什么呢?特别是在您可以连续使用运算符的情况下,例如cout<<x<<y
。
例如,在实现+操作“string +(string)”时。你将如何通过ref或val返回返回值。
答案 0 :(得分:64)
一些运算符按值返回,一些通过引用返回。通常,结果为新值(例如+, - 等)的运算符必须按值返回新值,并且运算符的结果是现有值,但已修改(例如&lt;&lt;&lt;&gt ;, &gt;,+ =, - =等),应该返回对修改后的值的引用。
例如,cout
是std::ostream
,将数据插入流是一种修改操作,因此要实现<<
运算符插入ostream
,运算符的定义如下:
std::ostream& operator<< (std::ostream& lhs, const MyType& rhs)
{
// Do whatever to put the contents of the rhs object into the lhs stream
return lhs;
}
这样,当您有cout << x << y
之类的复合语句时,首先计算子表达式cout << x
,然后计算表达式[result of cout << x ] << y
。由于<<
上的运营商x
会返回对cout
的引用,因此表达式[result of cout << x ] << y
与预期的cout << y
相同。
相反,对于“string + string”,结果是一个新字符串(两个原始字符串都保持不变),因此它必须按值返回(否则您将返回对临时的引用,这是未定义的行为)。
答案 1 :(得分:12)
要尝试回答有关字符串的问题,字符串的运算符+()几乎总是作为自由(非成员)函数实现,以便可以对任一参数执行隐式转换。那就是你可以这么说:
string s1 = "bar";
string s2 = "foo" + s1;
鉴于此,我们可以看到这两个参数都无法更改,因此必须将其声明为:
RETURN_TYPE operator +( const string & a, const string & b );
暂时忽略RETURN_TYPE。由于我们无法返回任何参数(因为我们无法更改它们),因此实现必须创建一个新的连接值:
RETURN_TYPE operator +( const string & a, const string & b ) {
string newval = a;
newval += b; // a common implementation
return newval;
}
现在,如果我们将RETURN_TYPE作为引用,我们将返回对本地对象的引用,这是一个众所周知的禁忌,因为函数外部不存在本地对象。所以我们唯一的选择是返回一个值,即副本:
string operator +( const string & a, const string & b ) {
string newval = a;
newval += b; // a common implementation
return newval;
}
答案 2 :(得分:6)
如果您希望运算符重载的行为类似于内置运算符,则规则非常简单;该标准确切地定义了内置运算符的行为方式,并将指示内置结果是rvalue
还是lvalue
。
您应该使用的规则是:
rvalue
,那么您的重载应返回引用lvalue
,则您的重载应返回值但是,你的重载不需要返回与内置相同的结果,尽管除非你有充分的理由不这样做,否则你应该做的事情。
例如,KennyTM在对另一个答案的评论中指出,<<
和>>
运算符的流重载会返回对左操作数的引用,这不是内置函数的工作方式。但是流接口的设计者做到了这一点,因此流I / O可以被链接。
答案 3 :(得分:3)
通常,您会在更改其操作内容值的操作中按引用返回,例如=
或+=
。所有其他操作都按值返回。
但这更像是经验法则。您可以设计您的操作员。
答案 4 :(得分:2)
根据操作员的不同,您可能需要按值返回。
当两者都可以使用时,例如在operator + =中,您可以考虑以下内容: