Thread: reading from file (polymorphism)

  1. #1
    Registered User
    Join Date
    May 2013
    Posts
    59

    reading from file (polymorphism)

    How to i read data from file into my program when there is 2 types of classes inside the file?

    In my txt file i have something like this.
    Code:
    Local  John  IC_number  State
    International  Bob  VisaNumber PassportNo
    I have something like this but Im not sure on how to continue from here.
    Code:
    int main()
    {
    string nationality;
    ifstream in(filename);
    
    vector <clsStudent*> student;
    
    if (in)
      {
          in >> nationality;
          if (nationality == "Local")
          {
              clsLocalStudent stud;
              stud.readFromFile(student);
          }
          else
          {
              clsInternationalStudent stud;
              stud.readFromFile(student)
          }
    }
    in.close();
    }
    
    
    void readFromFile(vector<clsStudent*> &s)
    {
    string ReadNationality, name, passportNumber, visa;
    
    ifstream in(filename);
       if(in)
       {
          in >> ReadNationality;
          in >> name;
          in >> passportNumber;
          in >> visa;
        }
        in.close();
        clsInternationalStudent *stud;
        stud = new clsInternationalStudent();
        
        stud.setNationality(ReadNationality);
        stud.setName(name);
        stud.setPassPortNo(passportNumber);
        stud.setVisa(visa)
        s.push_back(stud);
    }

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    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.
    Last edited by laserlight; 12-03-2013 at 05:56 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2013
    Posts
    59
    Can u explain this?
    Code:
    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);
                }
            }
    


    And why do you need to delete the iterator?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That part is the "simple factory". Basically, you instantiate the object of the appropriate derived class depending on the string. Once done, you let polymorphism happen in the reading to the object.

    Quote Originally Posted by Alexius Lim
    And why do you need to delete the iterator?
    You need to delete what you new. Notice that I dereferenced the iterator.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File IO with polymorphism
    By Alexius Lim in forum C++ Programming
    Replies: 7
    Last Post: 12-02-2013, 09:03 AM
  2. Replies: 4
    Last Post: 11-27-2013, 12:24 PM
  3. Replies: 3
    Last Post: 11-28-2012, 09:16 AM
  4. Replies: 3
    Last Post: 07-17-2011, 03:51 AM
  5. Replies: 13
    Last Post: 05-31-2009, 11:30 AM

Tags for this Thread