I suggest something like this:
Code:
class clsStudent
{
public:
// ...
friend std::istream& operator>>(std::istream& in, clsStudent& student);
// ...
private:
virtual void read(std::istream& in) = 0;
};
std::istream& operator>>(std::istream& in, clsStudent& student)
{
student.read(in);
return in;
}
void read(std::istream& in, std::vector<clsStudent*>& students)
{
string line;
while (getline(in, line))
{
stringstream ss(line);
string nationality;
if (ss >> nationality)
{
clsStudent* student = nullptr;
if (nationality == "Local")
{
student = new clsLocalStudent();
}
else if (nationality == "International")
{
student = new clsInternationalStudent();
}
else
{
// handle an input error?
}
if (student)
{
ss >> *student;
students.push_back(student);
}
}
}
}
void readFromFile(std::string filename, std::vector<clsStudent*>& students)
{
ifstream in(filename);
if (in)
{
read(in, students);
}
else
{
// handle file opening error?
}
}
int main()
{
vector<clsStudent*> students;
readFromFile(filename, students);
// ...
for (vector<clsStudent*>::iterator iter = students.begin(); iter != students.end(); ++iter)
{
delete *iter;
}
}
Each derived class will then implement the read member function (yes, you can override a private member function) to read the part of the line that comes after the "Local/International" header.
Note that my skeleton example is not exception safe in that the memory allocated will not be freed in the event an exception is thrown. The best way to make it exception safe (or at least come closer to exception safety) is to switch from a vector<clsStudent*> to a vector<shared_ptr<clsStudent>> or maybe a boost::ptr_vector<clsStudent>.
EDIT:
Especially if you have or anticipate more subclasses, or if you use this in more than one place, you may find that it is a good idea to separate this part:
Code:
if (nationality == "Local")
{
student = new clsLocalStudent();
}
else if (nationality == "International")
{
student = new clsInternationalStudent();
}
else
{
// handle an input error?
}
into a simple factory function that, given a label (e.g., "Local"), returns a pointer to a new instance of the derived class corresponding to that label.