我就直接进入正题了:
我有一个文本文件,其中包含书名列表。我知道如何读取文本文件,例如:
string word;
file >> word;
但是,假设我有一个名为“word”的类。是否可以这样做:
word myWord;
file >> myWord;
如果是,那么如何声明这样的对象?它会读取它包含的第一个公共(public)字符串吗?
感谢您的宝贵时间!
最佳答案
简单的答案是肯定的,您可以执行 file >> myWord;
,只要
正如您为您的类定义了 >>
运算符一样:
std::ostream&
operator>>( std::ostream& source, Word& word )
{
// ...
return source;
}
几个注意事项:
该运算符(operator)不能是成员;它必须是一个免费函数。 (如果是成员(member)的话,你的类(class)就是左手 参数。)如果它需要访问私有(private)数据,你可能有 使其成为
friend
。不要忘记错误检查以及约定
istream
错误。如果遇到无法解析的输入 在你的类中,你需要设置std::ios::failbit
。 (的 当然,很多时候,你会委托(delegate)给以前的 定义的>>
,如果失败,std::ios::failbit
已经 已设置。)
编辑:
至于你应该在新重载的运算符中做什么, 有几种可能性(小心地可以是 混合):
您可以调用现有的
>>
,例如,对于字符串或 内置类型。这是迄今为止最简单的,但它假设 您的输入可以轻松地根据以下内容进行唯一解析 现有的>>
,但这种情况很少见。您还可以使用未格式化的输入,例如
istream::get()
, 这通常与之前的解决方案并行使用, 输入分隔符或其他语法元素等内容 您的格式。或者您可以恢复为直接从
streambuf
,并解析它们。如果您有,这是合适的 例如,一些全新的类型。如果你走这条路,做 如果您读取了文件末尾,则不会忘记设置eofbit
,即使 否则你可以成功解析。如果你这样做,你就会 还必须在>>
顶部创建一个sentry
对象, 并且只有在良好的情况下才继续。 (也只有在这样的情况下operator>>
认为std::ios::good
是有道理的。你绝对不能 如果std::ios::good()
,则尝试从streambuf中读取字符 返回 false,并且您必须随时设置std::ios::eofbit
读取 EOF(这将导致所有 future 的调用std::ios::good()
返回 false)。这是非常重要的 我倾向于使用一个小的包装对象,并通读 它。
在所有情况下,您可能都需要调整格式
信息:作为一个简单的例子,如果您不想允许
输入中存在空格,但您仍在使用 >>
,您
应该设置nows(并在最后恢复它)。因此,大多数这样的
>>
运算符将首先保存格式化状态,并且
最后恢复它。 (这通常是通过
IOSave
类,无论如何,您应该将其包含在您的工具包中。)
再说一遍,如果输入格式有误,您
应设置failbit
。
作为一个简单的例子,考虑一个 >>
来表示一个简单的复杂
类:
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;
}
这是一个极其简单的例子。真正的复杂
例如,类也接受 a+ib 形式的输入。
但它应该让你了解你必须做的事情
编写这样的运算符时请考虑。
关于c++ - 直接读取对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18702804/