我直奔主题:
我有一个包含书名列表的文本文件。我知道如何阅读文本文件,例如:
string word;
file >> word;
但是,假设我有一个名为“word”的类。是否可以这样做:
word myWord;
file >> myWord;
如果是,那么必须如何声明这样的对象?它会读取它包含的第一个公共字符串吗?
感谢您的时间 !
我直奔主题:
我有一个包含书名列表的文本文件。我知道如何阅读文本文件,例如:
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,则绝对不能尝试从 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 形式的输入。但它应该让您了解编写此类运算符时必须考虑的事项。
当然不是。你必须>>
为你的类重载运算符word
。您可以作为成员函数或非成员函数执行此操作。要作为非成员重载,您可以编写:
fstream& operator >> (fstream& arg1,word& arg2)
{
}
如果此功能需要访问您的私人成员,word
可以使用:
class word{
// somewhere in your class add this line
friend fstream& operator >> (fstream&,word&);
}