C ++中运算符重载的返回值

时间:2010-02-25 20:05:39

标签: c++ operator-overloading

我对C ++中运算符重载的返回值有疑问。通常,我发现了两种情况,一种是按值返回,一种是按引用返回。那么这个规则是什么呢?特别是在您可以连续使用运算符的情况下,例如cout<<x<<y

例如,在实现+操作“string +(string)”时。你将如何通过ref或val返回返回值。

5 个答案:

答案 0 :(得分:64)

一些运算符按值返回,一些通过引用返回。通常,结果为新值(例如+, - 等)的运算符必须按值返回新值,并且运算符的结果是现有值,但已修改(例如&lt;&lt;&lt;&gt ;, &gt;,+ =, - =等),应该返回对修改后的值的引用。

例如,coutstd::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 + =中,您可以考虑以下内容:

  • 如果您的对象是不可变的,那么按值返回可能会更好。
  • 如果您的对象是可变的,最好通过引用返回。