79

你能解释一下返回值、引用值和 const 引用值之间的区别吗?

价值:

Vector2D operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

非常量参考:

Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

常量参考:

const Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

这有什么好处?我理解将 const 引用传递给函数背后的意义,因为您要确保不修改该引用指向函数内部的值。但是我对返回 const 引用的含义感到困惑。为什么返回引用优于返回值,为什么返回 const 引用优于返回非 const 引用?

4

5 回答 5

47

除非你写一些奇怪的东西,否则没有区别

(v1 += v2) = v3;

在第一种情况下,分配将是临时的,整体效果将是v1 += v2

在第二种情况下,分配将是 to v1,因此整体效果将是v1 = v3

在第三种情况下,不允许分配。这可能是最好的选择,因为这种怪异几乎肯定是一个错误。

为什么返回引用比返回值更好?

它可能更有效:您不必复制对象。

为什么返回 const 引用比返回非 const 引用更好?

您可以防止像上面的示例那样奇怪,同时仍然允许不那么奇怪的链接,例如

v1 = (v2 += v3);

但是,正如评论中所指出的,这意味着您的类型不支持与内置类型相同的(ab)使用形式,有些人认为这是可取的。

于 2014-02-14T11:26:52.260 回答
22

价值:

按值返回意味着您正在返回一个对象的副本。这对类提出了要求(它必须是可复制的或可移动的)。这意味着对于某些按值返回的类的对象可能很昂贵(在 RVO 或 NRVO 不起作用或被关闭的情况下)。这也意味着新对象独立于其他对象(取决于其设计)并且是其自身的价值。这可能是您应该从许多二元运算符(如 +、-、* 等)返回的内容。

非常量参考:

您确实返回了另一个对象的别名。非 const 的别名允许您修改别名对象。这是您应该从一些一元运算符中返回的内容,例如前缀 ++ 和 -- 和 *(取消引用),因为您通常希望能够修改返回的对象。

这由 operator>> 和 operator<< 为流重载返回。这允许链接运算符:

cout << 5 << "is greater then" << 1 << endl;
cin >> myInt >> myFloat;

当您想要允许像这样链接常规方法时,您还可以返回对 *this 的引用:

object.run().printLastRunStatistics();

常量参考:

像上面一样,但你不能修改别名对象。当要返回的对象复制成本很高并且您可以在从函数返回后确保其存在时,可以使用而不是按值返回。

这就是 operator= 通常返回以允许以标准类型支持它们的方式进行多个赋值:

a = b = c;

operator= 中使用的常量引用防止了这种用法(据我记得标准类型不支持):

++(a = b);

如果使用正常参考,这将是允许的。

于 2014-02-14T11:44:13.133 回答
13

按值返回和按引用返回之间的区别在运行时生效:

当您按值返回对象时,将调用复制构造函数,并在堆栈上创建一个临时实例。

当您通过引用返回对象时,上述所有操作都不会发生,从而提高了性能。


return-by-referencereturn-by-constant-reference之间的区别没有运行时影响,只是为了防止您编写错误的代码。

例如,使用Vector2D& operator += (const Vector2D& vector),您可以执行以下操作:

(x+=y)++(x+=y).func()哪里func是类中的非常量函数Vector2D

但是const Vector2D& operator += (const Vector2D& vector),对于任何类似的尝试,编译器都会生成错误。

于 2014-02-14T11:36:11.890 回答
6

它与将参数传递给函数完全相同。

const当您返回一个对象的属性时,您希望返回一个引用,您不想在它之外进行修改。例如:当您的对象有名称时,您可以制作以下方法const std::string& get_name(){ return name; };。这是最优化的方式。您允许对内部属性进行“只读”访问,而没有返回时复制。

当您重载运算符时,您应该返回一个可变对象,否则某些通常预期可以工作的某些语法会产生错误。当您尝试一些奇怪的链接时,这非常重要。

例如,选项 3 不适用于(v1 += v2).non_const_method(), While,以下内容:

v1+=v2;
v1.non_const_method();
于 2014-02-14T11:27:10.840 回答
1

正如所指出的,但 luk32 只是为了确保不允许对此函数返回的对象进行任何更改。这基本上可以帮助您在编译时找到逻辑错误。假设您确定不更改对象,并且您的代码正在更改对象,则可以对其进行跟踪。它可以被认为是一个很好的编码实践。

于 2014-02-14T11:32:38.877 回答