为什么我们需要在重载 >> 和 << 运算符时返回对 istream/ostream 的引用?

Why we need to return reference to istream/ostream while overloading >> and << operators?

提问人:Rajat 提问时间:3/7/2015 最后编辑:Vlad from MoscowRajat 更新时间:7/24/2019 访问量:9122

问:

如果我不返回会发生什么,或者,实际上我正在阅读一本书,其中作者返回回流引用dindout

istream & operator>>(istream &din,vector &a)
{
    for(int i=0;i<size;i++)
    din>>a.v[i];
    return din;
}

ostream & operator<<(ostream &dout,vector &a)
{
    dout<<"("<<a.v[0];
    for(int i=1;i<size;i++)
    dout<<", "<<a.v[i];
    dout<<")";
    return dout;
}
C++ 引用 运算符重载

评论


答:

5赞 Vlad from Moscow 3/7/2015 #1

在这种情况下,当返回引用时,您可以在链中组合运算符。例如

std::cout << "Hello " << "Rajat Verma";

这等效于操作员的以下调用

operator <<( operator <<( std::cout, "Hello" ), "Rajat Verma" );
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
              returns reference to std::cout 
3赞 youssef 3/7/2015 #2

还有一件事是 ostream 和 istream 标准对象(如 cout 和 cin)使用私有副本构造函数,因此它们应该通过引用而不是值返回

16赞 Walter 3/7/2015 #3

原因是几个事实的结合。

  1. 您希望能够链接输入和输出操作,如下所示

    in  >> x >> y;
    
    out << z << std::precision(10) << t << std::endl;
    

    因此,您必须返回允许再次返回的东西。operator<<

  2. 因为你希望你的运算符处理任何 ,即派生自 的任何对象,所以你不能定义istreamstd::istream

    operator<<(istream_type, object);    // take istream by value
    

    因为这只适用于特定的 istream 类型,而不适用于通用 .为此,必须使用多态性,即要么接受引用,要么接受指针(这将是指向派生自的类的引用或指针)。istream_typeistreamstd::istream

  3. 由于您只有对 istream 的引用,因此您不能返回 istream 对象本身(该对象可能是在定义时甚至没有定义的类型),而只能返回您获得的引用。operator<<

    可以通过定义 a 并获取并返回 by 值来绕过此限制,但这要求类型具有复制构造函数,而它很可能没有充分的理由。operator<<templateistream_typeistream

  4. 为了支持多态性,原则上可以使用指针(指向流)而不是引用。但是,是 在 C++ 中不允许(至少一个操作数必须是类或枚举类型)。operator<<(stream*,const char*)

    因此,对于流指针,必须使用函数调用语法,而您又回到了 C 样式。fprintf(stream*, args...)

    此外,指针可以是 null 或悬空的,这实际上是它们的默认状态(在没有初始值设定项的情况下声明时),而引用可以假定为有效(在没有初始值设定项的情况下不能声明)。

评论

3赞 The Paramagnetic Croissant 3/7/2015
我不确定你关于指针的最后一个论点是否切中要害。如果这些运算符返回指针,我们将不得不称它们为 - 当然没有人会想要这种语法混乱。*(*(out << foo) << bar) << baz;
0赞 Walter 3/7/2015
@TheParamagneticCroissant 没有你没有明白我的意思。我编辑了答案。人们可以(拥有)使用(d)指针而不是所有地方的引用,包括标准库,它将像引用一样工作,期望出现空指针和/或悬空指针的问题。
1赞 Rob 3/7/2015
指针的“默认状态”不是“NULL 或 dangling”,并且无需使用指针即可轻松创建悬空引用。将引用与流函数一起使用的原因是为了允许链接,也因为使用引用允许运算符假定对象存在(即调用方负责提供有效的引用,并且运算符不需要像使用指针那样检查有效性)
0赞 Walter 3/7/2015
@Rob,我认为你的最后一点就是我所说的空指针或悬空指针的意思。声明不带初始化器的指针为 null 或悬空。如果没有初始化器,则无法声明引用。
0赞 The Paramagnetic Croissant 3/7/2015
@Walter如果在参数中使用指针,则无法在右值流上调用这些运算符。我已经看到 C++ 之前的代码正在做.std::stringstream(the_string) >> the_int
-1赞 Arda 3/7/2015 #4

键入时: cout <<向量; cout 具有 ostream 类型,所以当你使用 “<<” 时,它确实需要返回一个带有 ostream 类型的参数才能使 cout 工作