Imagine a class named Poet, with a member FirstName, LastName and class named Verse as Poet's member. is it possible to construct Poet with ifstream, then initialize FirstName and LastName with ifstream, then construct member Verse with the same ifstream? I mean, how can I pass ifstream correctly from one class to it's member class after initializing some members? Thanks.
Step 1: add operator >> to Verse
This is an utterly trivial >>
based on What are the basic rules and idioms for operator overloading?
Since I don't know what's supposed to go inside a Verse
, I'm sticking with the literal definition of one line.
friend std::istream& operator>>(std::istream& in, Verse & obj)
{
std::getline(in, obj.line);
return in;
}
This lets you read from any stream, not just fstream
, into a Verse
. Where it makes sense, work from the highest level of abstraction to get a more general solution.
Step 2: Use Verse
's >>
in the constructor.
I'm flipping a coin over whether or not this is a good thing to do in a constructor. A constructor, like any other function, should do one job. A constructor's job is initialize an object. Reading in from a file may can often overstep the one job rule. Another reason is there are (or should be) only two ways out of a constructor: With an initialized object or a thrown exception and exceptions are expensive. IO has a lot of room for error, so you may find yourself throwing an exception more often than you'd like.
Poet(std::istream & in)
{
in >> FirstName >> LastName >> Verse;
if (!in)
{
throw std::runtime_error("Aaaaaaaarrrggghhhh!");
}
}
Note again I've widened the input stream from a file stream to all istream
s to generalize the function.
Also not the exception if there are any failures reading. You get an object or you don't.
Final note (Baring edits) this solution fails horribly in the face of poet names like "Johann von Goethe" because it will only accept one-word names.