2

我直奔主题:

我有一个包含书名列表的文本文件。我知道如何阅读文本文件,例如:

string word;
file >> word;

但是,假设我有一个名为“word”的类。是否可以这样做:

word myWord;
file >> myWord;

如果是,那么必须如何声明这样的对象?它会读取它包含的第一个公共字符串吗?

感谢您的时间 !

4

2 回答 2

3

简单的答案是肯定的,你可以这样做file >> myWord;,只要你>>为你的类定义了操作符:

std::ostream&
operator>>( std::ostream& source, Word& word )
{
    //  ...
    return source;
}

几个考虑:

  • 该运营商不能成为会员;它必须是免费功能。(如果它是成员,您的类将是左手参数。)如果它需要访问私有数据,您可能必须将其设为friend.

  • 不要忘记错误检查和错误的约定 istream。如果遇到无法解析到类中的输入,则需要设置std::ios::failbit. (当然,很多时候,您将委托给先前定义>>的,如果它们失败,std::ios::failbit则已经设置了。)

编辑:

至于你应该在新重载的运算符中做什么,有几种可能性(可以小心混合):

  • >>例如,您可以为字符串或内置类型调用现有的。这是迄今为止最简单的,但它假设您的输入可以很容易地根据现有的唯一解析>>,这种情况很少见。

  • 您还可以使用未格式化的输入,例如istream::get(),这通常与先前的解决方案并行使用,以输入诸如分隔符或格式的其他语法元素之类的内容。

  • 或者,您可以恢复直接从 中读取字节 streambuf并解析它们。例如,如果您有一些全新的类型,这是合适的。如果您走这条路线,请 不要忘记设置eofbit是否读取文件结尾,即使您可以成功解析。如果你这样做,你还必须sentry在你的顶部创建一个对象>>,并且只有在它好的时候才继续。(只有这样 operator>>才有std::ios::good意义。如果std::ios::good() 返回 false,则绝对不能尝试从 streambuf 读取字符,并且必须std::ios::eofbit在读取 EOF 的任何时候设置(这将导致所有将来的调用 std::ios::good()返回 false)。就是这样重要的是我倾向于使用一个小的包装对象,并通读它。

在所有情况下,您可能都必须使用格式信息:作为一个简单的示例,如果您不想在输入中允许空格,但您仍在使用>>,您应该设置nows(并在最后恢复它)。因此,大多数这样 >>的操作员会从保存格式化状态开始,并在最后恢复它。(这通常是通过一个 IOSave类来完成的,无论如何你都应该在你的工具包中拥有它。)同样,如果输入格式中的某些内容不正确,你应该设置failbit.

作为一个简单的例子,考虑一个>>简单的Complex 类:

std::istream&
operator>>( std::istream& source, Complex& dest )
{
    IOSave state( source );
    //      Skip leading whitespace, depending on formatting options.
    if ( (source.flags() & std::ios_base::skipws) != 0 ) {
        source >> std::ws;
    }
    source.unsetf( std::ios_base::skipws );
    std::streamsize totalWidth
        = std::max( source.width() - 3, std::streamsize(0) ); ;
    std::streamsize imagWidth = totalWidth / 2;
    std::streamsize realWidth = totalWidth - imagWidth;
    if ( source.get() != '(' ) {
        source.unget();
        source.setstate( std::ios::failbit );
    }
    double real = 0.0;
    source >> std::setw( realWidth ) >> real;
    std::numpunct<char> const& np
        = std::use_facet<std::numpunct<char>>( source.getloc() );
    if ( std::get() != (np.decimal_point() != ',' ? ',' : ';') ) {
        source.unget();
        source.setstate( std::ios::failbit );
    }
    double imag = 0.0;
    source >> std::setw( imagWidth ) >> imag;
    if ( std::peek() != ')' ) {
        source.unget();
        source.setstate( std::ios::failbit );
    }
    if ( source ) {
        dest = Complex( real, imag );
    }
    return source;
}

这是一个极其简单的例子。例如,一个真正的Complex 类也会接受 a+ib 形式的输入。但它应该让您了解编写此类运算符时必须考虑的事项。

于 2013-09-09T17:36:37.427 回答
1

当然不是。你必须>>为你的类重载运算符word。您可以作为成员函数或非成员函数执行此操作。要作为非成员重载,您可以编写:

fstream& operator >> (fstream& arg1,word& arg2)
{
}

如果此功能需要访问您的私人成员,word可以使用:

class word{
    // somewhere in your class add this line
    friend fstream& operator >> (fstream&,word&);
}
于 2013-09-09T16:31:12.810 回答