The simple answer is yes, you can do file >> myWord;
, as long
as you've defined the >>
operator for your class:
std::ostream&
operator>>( std::ostream& source, Word& word )
{
// ...
return source;
}
Several considerations:
This operator cannot be a member; it must be a free function.
(If it were a member, your class would be the left hand
argument.) If it needs to access private data, you might have
to make it a friend
.
Don't forget about error checking, and the conventions of
istream
for errors. If you encounter input you cannot parse
into your class, you need to set std::ios::failbit
. (Of
course, a lot of the time, you'll be delegating to previously
defined >>
, and if they fail, std::ios::failbit
will already
have been set.)
EDIT:
As for what you should do inside the newly overloaded operator,
there are several possibilities (which can, with care, be
mixed):
You can invoke existing >>
, for example, for strings or
built-in types. This is by far the easiest, but it supposes
that your input can easily be parsed uniquely in terms of
existing >>
, which is rarely the case.
You can also use unformatted input, like istream::get()
,
this is most often used in parallel with the previous solution,
to input things like separators, or other syntactical elements
of your format.
Or you can do revert to reading the bytes directly from the
streambuf
, and parse them. This is appropriate if you have
some totally new type, for example. If you go this route, do
not forget to set eofbit
if you read an end of file, even if
you can successfully parse otherwise. If you do this, you'll
also have to create a sentry
object at the top of your >>
,
and only proceed if it is good. (It is only in such
operator>>
that std::ios::good
makes sense. You must never
try to read a character from the streambuf if std::ios::good()
returns false, and you must set std::ios::eofbit
anytime you
read an EOF (which will cause all future calls to
std::ios::good()
to return false). This is so essential that
I tend to use a small wrapper object for it, and read through
it.
In all cases, you may have to play around with the formatting
information: as a simple example, if you don't want to allow
white space within your input, but you are still using >>
, you
should set nows
(and restore it at the end). Thus, most such
>>
operators will start by saving the formatting status, and
restore it at the end. (This is usually done by means of an
IOSave
class, which you should have in your toolkit anyway.)
And again, if something in the input format is incorrect, you
should set failbit
.
As a simple example, consider a >>
for a simple 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;
}
This is an extremely simplistic example. A real Complex
class would, for example, also accept input in the form a+ib.
But it should give you an idea of the sort of things you have to
consider when writing such an operator.