直接读取对象

Reading directly to an object

本文关键字:取对象 读取      更新时间:2023-10-16

我会直奔主题:

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

string word;
file >> word;

但是,假设我有一个名为"word"的类。是否有可能做到:

word myWord;
file >> myWord;

如果是,如何声明该对象?它会读到它包含的第一个公共字符串吗?

谢谢你的时间!

简单的答案是肯定的,你可以做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,并且您必须随时设置 std::ios::eofbit读取 EOF(这将导致所有将来的调用 std::ios::good()返回假)。 这太重要了,以至于我倾向于使用它使用一个小的包装器对象,并通读它。

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

作为一个简单的示例,请考虑简单Complex>>.class:

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 形式的输入。但它应该让你了解你必须做的事情。编写这样的运算符时要考虑。

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

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

如果此函数需要访问word的私有成员,您可以使用:

class word{
    // somewhere in your class add this line
    friend fstream& operator >> (fstream&,word&);
}