Перегрузка оператора извлечения для двух классов

можно ли написать оператор извлечения при чтении из файла для переменных-членов в двух классах? Первый класс — CPerson, который содержит имя и EGN (номер социального страхования), а второй класс — CStudent, который содержит FN (номер факультета) и карту с различными тестами (код теста и заработанные баллы). В настоящее время я перегрузил оператор извлечения для класса CStudent, что означает, что у меня есть доступ к его закрытым членам, но я хотел бы сделать то же самое для CPerson, поэтому мне также не нужно использовать функции установки для этого класса. .

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();
    }
};

Если нужно, вот содержимое одного из файлов:

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

Обновлены операторы:

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;
}

Результат:

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

person Arirang    schedule 20.03.2015    source источник
comment
Нет конструктора копирования ни для CPerson, ни для CStudent. Также я не вижу конструктора по умолчанию. Я действительно не знаю, если это проблема, я просто комментирую.   -  person Barmak Shemirani    schedule 20.03.2015


Ответы (1)


Вы можете прочитать name и EGN в 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;
}

Извлечение в CStudent сначала извлечет данные в CPerson (имя и EGN должны быть вашими первыми строками во входных данных):

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;
}

Несколько предлагаемых улучшений:

CStudent student; // you will need default constructor for this

while(st >> student)
    students.push_back(student); // read like this in CGroup

Пройдите std::string мимо const&. Ограничивать себя const в этих параметрах без привязки почти ни к чему.

CGroup(string const& filename);
CPerson(string const& n, string const& e)
person LogicStuff    schedule 20.03.2015
comment
Я сделал что-то не так с операторами, что вызывает бесконечный цикл. Я разместил обновленные операторы в нижней части исходного сообщения. - person Arirang; 20.03.2015
comment
Похоже, проблема связана с функцией CGroup. Если я просто удалю цикл st.eof(), он правильно извлечет всю информацию для первого ученика в каждом файле. К сожалению, предложенное вами улучшение для CGroup не дало эффекта. - person Arirang; 20.03.2015
comment
@Arirang На самом деле, вы должны читать с std::getline и std::istringstream, извините за это. Попробуйте настроить функции и дайте мне знать, если это сработает. - person LogicStuff; 20.03.2015
comment
Я внес изменения, но теперь он вставляет ученикам в группу тесты, которых у них обычно нет. Могу ли я как-то очистить поток, чтобы этого не произошло? Я обновил оператора в исходном посте, а также результат. Имейте в виду, что учащиеся в результате сортируются на основе их средних баллов по результатам тестов. - person Arirang; 20.03.2015
comment
Я только что увидел, что вы обновили свою функцию с помощью stringstream, но результаты те же. - person Arirang; 20.03.2015
comment
Хорошо, я нашел проблему, из-за которой карта тестов была заполнена несуществующими тестами. Предложенное вами улучшение использования while(st ›› student) в конструкторе CGroup на самом деле вызывало проблему. Когда я вернулся к тому, как это было раньше, с помощью while(!st.eof()), он начал правильно читать тесты. Тем не менее, большое спасибо за вашу помощь, я действительно понятия не имел, как иметь операторы извлечения для двух классов. - person Arirang; 20.03.2015
comment
Пожалуйста. Я постараюсь выяснить, что с ним не так. - person LogicStuff; 20.03.2015