【问题标题】:Simple questions about cin/cout overloading关于 cin/cout 重载的简单问题
【发布时间】:2010-07-16 22:22:46
【问题描述】:

我知道这是非常基本的,但到目前为止我一直在猜测。

Foo 只是一个从字符串类私有继承的对象,这就是我强制转换它的原因。使用 Primer C++ (Prata's) 中的示例

所以如果我有这样的功能:

istream & operator>>(istream & is, Foo & f)
{
      is >> (string &)f;
      return is;
}

int main()
{

Foo f;


cin >> f; 

}

所以,一旦 cin >> f 被命中,函数就会被调用,并且现在的字符串被存储在 istream 引用中。现在返回 istream 对象,现在...?返回的 istream 对象的内容(字符串)现在是否自动放置在 f 中?还是我错过了了解 cin 工作原理的一步?

另外,如果我这样做:

int x;

cin >> f >> x;

它会隐含地是什么样子?喜欢 (cin) >> x?

最后,还有一件简单的事情。如果在一个函数中(其中包含一个 ostream 引用),我在一个循环中传递每个数组项并执行此操作:

for(int i=0;i < 5;i++)
{
os << array[i] << "\n";
}

ostream 对象是否只是在其自身中复合了每个数组项?

【问题讨论】:

  • Foo 中有什么内容?为什么要将它转换为引用字符串?
  • 忘了说,继承自字符串类,所以需要强制转换 Foo 对象。仅使用 Prata 的入门示例中的一部分。
  • 为什么不直接删除Foo 避免混淆?

标签: c++


【解决方案1】:

如果将重载的运算符替换为普通的函数调用,这将变得非常容易。 cin &gt;&gt; f 简单翻译为:

operator >>(cin, f);

现在将cin &gt;&gt; f &gt;&gt; x 视为(cin &gt;&gt; f) &gt;&gt; x。这转化为:

operator >>(operator >>(cin, f), x);

由于第一个运算符返回cin,所以在执行过程中,这实际上变成了:

operator >>(cin, x);

int 等原始数据类型通常在流类本身内被重载,因此它实际上看起来像这样:

cin.operator >>(x);

您可以自行扩展它以回答您关于 ostream 的问题 - 它的工作方式完全相同。

【讨论】:

    【解决方案2】:
    istream & operator>>(istream & is, Foo & f)
    {
          is >> (string &)f;
          return is;
    }
    

    istream&amp; operator&gt;&gt;(istream&amp; is, string&amp; f)(好吧,basic_istream&lt;T&gt;&amp;, basic_sttring&lt;T&gt;&amp;)已经存在。因此,虽然您可以这样做,但为什么要这样做?

    所以,一旦 cin >> f 被命中,函数就会被调用并且现在的字符串被存储在 istream 引用中

    不,流由istream&amp; operator&gt;&gt;(istream&amp; is, string&amp; f) 使用,它将字符串(的存储)设置为包含消耗字节的表示形式。

    然后返回对 istream 的引用。

    int x;
    cin >> f >> x;
    

    相当于:

    int x;
    (cin >> f) >> x;
    

    因为操作符关联规则,并且是“真的”:

    int x;
    std::operator>>( ::operator>>(cin,  f), x ) ;
    

    其中两个operator&gt;&gt;s 是op&gt;&gt; 的两个不同 重载版本,也就是说,您的版本(在全局命名空间中)采用istream 和Foo 是内部版本,它返回对 istream 的引用,而 istream 又是外部参数的第一个参数,即 std 命名空间中采用 istream 和 int 的参数。

    ostream 对象是否只是在其自身中复合了每个数组项?

    每个对象,无论array[n] 是什么类型,都被添加到ostream,按顺序,添加到流中,后跟换行符。所以“复合”是一种不好的表达方式,但是是的。自然,需要存在一个op&lt;&lt;( ostream&amp;, const X&amp;),其中“X”是 array[n] 的任何类型(或隐式可转换为)。

    【讨论】:

      【解决方案3】:

      当您执行cin &gt;&gt; f 时,重载解析会选择您重载的 istream &gt;&gt; 重载并调用它。然后,在您的重载中,您从流中提取 string,它调用采用 istream 和 string&gt;&gt; 重载。

      请注意,从std::string 派生是最不寻常的,即使是私下。相反,您可能应该使用组合:有一个std::string 类型的成员变量。

      你的演员阵容相当混乱;如果你有一个 std::string 类型的成员变量,那么你可以使用更自然的语法来提取它:

      is >> f.stringmembervariable;
      

      cin &gt;&gt; f &gt;&gt; x 首先从cin 中提取Foo 并将其存储在f 中,然后从cin 中提取int 并将其存储在x 中。假设所有 &gt;&gt; 重载都遵循返回它们传递的 istream 的约定,那么实际上就像您要说的一样:

      cin >> f;
      cin >> x;
      

      这就是为什么您应该从 &gt;&gt; 重载中返回 istream,以便可以像这样链接提取。

      至于你的最后一个问题,无论array[i] 是什么类型,都会在循环内调用重载的ostream &lt;&lt; 运算符。

      【讨论】:

        【解决方案4】:

        当你这样做时:

        cin >> f;
        

        您是正确的,您的操作符函数将被调用,并且 cin 上的任何字符串现在都将存储在 f 中。

        当你这样做时:

        cin >> f >> x;
        

        真正发生的是你的函数和以前一样被调用,但是它返回了 cin。由于没有为 istream 和 int 定义重载 >>,因此 cin 将被正常处理。

        首先,计算机会计算:

        cin >> f;
        

        它会被你的函数重载。然后计算机计算:

        cin >> x;
        

        这是cin和整数的正常运算。

        你的线路也会发生同样的事情:

        os << array[i] << "\n";
        

        其中:

        os << array[i];
        

        先处理,然后:

        os << "\n";
        

        得到处理。

        从技术上讲,在这两种情况下,您的流对象都会被返回,但是没有使用返回值,所以它只是被丢弃了。这将与以下内容相同:

        sqrt(81);
        

        由于没有变量来存储返回值,计算机将计算该值然后丢弃它(如果你的编译器很聪明,则完全跳过它)。

        【讨论】:

        • "没有为 istream 和 int 定义重载>>:"有;它是basic_istream 的成员函数。
        • 那么(对于我给出的最后一个示例),如果我返回 os 对象,编译器会如何看待它?所以如果上面的函数被重载做了类似 cout
        • 如果你返回一些东西,而那个返回值没有被使用,它就会被简单地丢弃。这就是我之前展示的 sart(81) 的情况。但是,如果您正在执行类似 (cout
        猜你喜欢
        • 2013-07-17
        • 1970-01-01
        • 1970-01-01
        • 2011-05-19
        • 2011-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多