c++extraction-operator

Overloading extraction operator for two classes


is it possible to write an extraction operator when reading from a file for member variables in two classes? The first class is CPerson, which contains name and EGN (social security number), and the second class is CStudent, which contains FN (faculty number) and a map with various tests (code of test and earned points). Currently I have overloaded an extraction operator for the class CStudent, which means that I have access to its private members, but I would like to do the same thing for CPerson, so I don't need to use setter functions for that class as well.

class CPerson
{
private:
    string name;
    string EGN;

public:
    CPerson(const string n, const string e)
    {
        name=n;
        EGN=e;
    }
    void setname(const string n) {name=n;}
    void setEGN(const string e) {EGN=e;}
};

class CStudent: public CPerson
{
private:
    string FN;
    map<int, int> st_tests;

public:
    CStudent(const string o, const string p, const string n):CPerson(o,p)
    {FN=n;}
    friend istream &operator>> (istream &, CStudent &);
};

istream &operator>> (istream &input, CStudent &c)
{
    string z, x, y, line;
    int d, e;

    getline(input,line);
    istringstream ln(line);
    ln >> z >> x >> c.FN;
    c.setname(z);
    c.setEGN(x);

    while(true)
    {
        ln >> d >> e;
        c.st_tests[d] = e;
        if(!ln.good())
            break;
    }
    return input;
}

class CGroup
{
private:
    string spec; //specialty
    int kurs; //course
    int grupa; //group
    vector<CStudent> students; //vector of CStudent objects

public:
    CGroup(const string filename) //constructor with name of file to be read as parameter
    {
        string a;
        int b, c;
        ifstream st;
        st.open(filename.c_str(),ios::in);
        if(!st)
        {
            cout<<"Cannot open "<<filename<<" or file does not exist."<<endl;
            exit(1);
        }
        string line;
        getline(st,line);
        istringstream group(line);
        group >> a >> b >> c;
        spec = a;
        kurs = b;
        grupa = c;
        while(!st.eof())
        {
            CStudent student;
            st >> student;
            students.push_back(student);
        }
        st.close();
    }
};

If it's needed, here are the contents in one of the files:

KST 1 1
Ivan 9404019382 61360125 1 55 2 90 3 78 12 82 13 99 14 78 15 72
Kaloqn 9311281029 61360126 1 82 2 43 3 95 13 50
Airqn 9408132918 61360127 1 91 2 40 3 89
Mariq 9409071824 61360128 1 55 2 91 3 78 16 0
Ginka 9312198212 61360129 1 87 2 84 3 15
Leika 9405221982 61360130 1 25 2 76 3 56
Shumaher 9305119225 61360131 1 94 2 75 3 92
Onzi 9408108876 61360132 1 40 2 59 3 49

Updated operators:

CPerson
{
    friend istream &operator>> (istream &, CPerson &);
};

istream &operator>> (istream &input, CPerson &c)
{
    input >> c.name >> c.EGN;
    return input;
}

istream &operator>> (istream &input, CStudent &c)
{
    int d, e;
    string line;
    getline(input,line);
    istringstream ln(line);
    ln >> static_cast<CPerson&>(c) >> c.FN;
    while(ln >> d >> e)
        c.st_tests[d] = e;
    return input;
}

Result:

Ivan 9404019382 61360125 1 55 2 90 3 78 12 82 13 99 14 78 15 72
Kaloqn 9311281029 61360126 1 82 2 43 3 95 12 82 13 50 14 78 15 72
Airqn 9408132918 61360127 1 91 2 40 3 89 12 82 13 99 14 78 15 72
Mariq 9409071824 61360128 1 55 2 91 3 78 12 82 13 99 14 78 15 72 16 0
Ginka 9312198212 61360129 1 87 2 84 3 15 12 82 13 99 14 78 15 72 16 0
Leika 9405221982 61360130 1 25 2 76 3 56 12 82 13 99 14 78 15 72 16 0
Shumaher 9305119225 61360131 1 94 2 75 3 92 12 82 13 99 14 78 15 72 16 0
Onzi 9408108876 61360132 1 40 2 59 3 49 12 82 13 99 14 78 15 72 16 0

Solution

  • You could read name and EGN in CPerson:

    istream &operator>> (istream &input, CPerson &c)
    {
        // this is friend function, so you can access private members of CPerson
        input >> c.name >> c.EGN; // or something similar...
        return input;
    }
    

    Extraction to CStudent will extract data to CPerson first (name and EGN should be your first strings in input data):

    istream &operator>> (istream &input, CStudent &c)
    {
        input >> static_cast<CPerson&>(c); // read CPerson's data first
    
        string line;
    
        if(getline(input, line))
        {
            istringstream iss(line);
    
            while(iss >> d >> e) // then read CStudent's special data
                c.st_tests[d] = e;
        }
    
        return input;
    }
    

    A few suggested improvements:

    CStudent student; // you will need default constructor for this
    
    while(st >> student)
        students.push_back(student); // read like this in CGroup
    

    Pass std::string by const&. Restricting yourself with const in these parameters is almost to no use without reference.

    CGroup(string const& filename);
    CPerson(string const& n, string const& e)