繁体   English   中英

为什么我们将对对象的引用作为参数传递给重载的输出运算符

[英]Why do we pass a reference to the object as an argument to the overloaded output operator

为什么作为引用而不只是对象的副本如此重要? 例如:

ostream& operator<<(ostream& out, const X & _class);
ostream& operator<<(ostream& out, const X   _class);

如果我们不将其作为参考,我们会输/赢什么?

通常,首选const& ,因为除了易于复制的类型(例如基本类型)之外,复制非常昂贵(我记得并不总是如此)。 但是请注意,按值传递意味着函数的内部值与传递给函数的值无关。 这使编译器可以做一些假设,并在某些情况下执行更好的优化。 因此,在某些情况下,按价值传递更好。

其中一种情况是您需要传递的参数的副本:

void f( T param )
{
    /* do something mutable with param */
}

在那种情况下,按值传递比通过const引用+手工复制传递更可取,因为编译器可以基于值语义进行假设并优化代码。 规则是:让编译器决定如何按值传递。

对于流,C ++流不可复制,这就是为什么它们通过引用传递的原因。 是非常量引用,因为IO操作会更改流的内部状态。

在一般情况下,将const&传递给函数会更有效,因为它避免了复制。

“合理的悲观主义”将总结我们这样做的原因,以及实际上为什么我们更喜欢为不需要副本的任何非平凡对象传递引用。

我们可以很悲观地认为,对于本机类型以外的任何其他内容,与通过引用访问对象相比,创建副本效率低下。

我们还可以期望并非所有对象都是可复制的,因此编写一个要求我们的参数可复制的函数不仅可能导致效率低下,而且还很可能导致程序无法编译。

我们还可以期望某些对象的副本构造函数会产生副作用(例如不建议使用的auto_ptr)。 如果我们只想查询对象的状态,那么这些副作用是不可取的。 对于auto_ptr,它们将导致在函数末尾删除由auto_ptr控制的对象。 灾难性的。

一般规则是:

  • 如果您只是要读取对象,请传递const引用
  • 如果要修改对象,请传递引用(或指针)。
  • 如果您肯定要复制该对象,请按值传递它。
  • 如果您可能要进行复制,则可以通过const引用(乐观地说我们不需要进行复制)或通过值(可以合理地确信需要复制)来传递。

答案很明显。 因为如果您不这样做,那么实际的对象将不会被修改。 取而代之的是,将制作一个副本并对其进行修改,然后,该副本将被销毁。

如果不是const引用,则需要定义一个复制构造函数以使其正确,并且调用复制构造函数显然会花费更多的内存和CPU,这实际上是不必要的。

让我直说吧。 当您传递对象的引用并在重载运算符的定义中修改对象的内容时,相同的内容也会反映在对象上。 例如:(尽管对于复杂的数字,+运算符永远不会以这种方式重载,但是该示例只是为了证明这一点)。 说一个重载+运算符

complex1& operator+(complex1 a)
    {
        a.real = a.real+1;
        real=real+a.real;
        img=img+a.img;
        return *(this);
    }

int main()
{
    complex1 c1(1,2),c2(2.4,6.3);
    complex1 c3 = c1+c2;
    cout<<c2;
    return 0;
}

在这里,在c2的实部所做的更改(即1的加法)在打印时不会反映出来,如果未通过引用,则仍为2.4。 因此,传递参考将使其实部的值增加1。

其次,传递引用更为有效,因为您仅传递对该对象的引用,而不像按值传递那样复制对象的所有属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM