0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 51
1

Виртуальные базовые классы и деструкторы

05.09.2018, 00:36. Показов 2156. Ответов 4

Студворк — интернет-сервис помощи студентам
Пожалуйста, помогите разобраться. Решаю задачу 6 глава 17 из Праты. Кратко: в определении виртуального абстрактного класса определяю деструктор:
C++
1
virtual ~abstr_emp() = 0 {};
В процессе освобождения памяти, выделенной динамически в массиве указателей, по цепочке вызываются деструкторы по умолчанию вплоть до этого
C++
1
virtual ~abstr_emp() = 0 {};
(В функции:
C++
1
2
3
4
5
6
7
void free(abstr_emp** pc, int nn)
{
    for (int i = 0; i < nn; i++)
    {
        delete pc[i];
    };
}
И здесь выскакивает исключение:
Exception thrown: read access violation.
_Pnext was 0x38E9DC.

Указывает на (если это поможет):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// MEMBER FUNCTIONS FOR _Container_base12
inline void _Container_base12::_Orphan_all()
    {   // orphan all iterators
 #if _ITERATOR_DEBUG_LEVEL == 2
    if (_Myproxy != 0)
        {   // proxy allocated, drain it
        _Lockit _Lock(_LOCK_DEBUG);
 
        for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter;
            *_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter)    // - ошибка!
            (*_Pnext)->_Myproxy = 0;
        _Myproxy->_Myfirstiter = 0;
        }
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */
    }
Причем ошибка возникает с данными, кот были считаны из бинарников. При первом запуске и записи в бинарник освобождение памяти идет на ура.

Полный код программы:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#pragma once
#ifndef EMP_H
#define EMP_H
 
#include <iostream>
#include <fstream>
#include <string>
 
using std::string;
using std::ofstream;
using std::ostream;
using std::ifstream;
 
enum classType { Employee, Manager, Fink, Highfink };
 
class abstr_emp
{
private:
    string fname;
    string lname;
    string job;
public:
    abstr_emp() : fname("Noname"), lname("No_last_name"), job("No_job") {};
    abstr_emp(const string & fn, const string & ln, const string & j) :
        fname(fn), lname(ln), job(j) {}
    virtual void ShowAll() const;
    virtual void SetAll();
    friend ostream& operator<<(ostream &os, const abstr_emp & e);
    virtual ~abstr_emp() = 0 {};
    virtual bool writeall(ofstream & fout) const;
    virtual bool getall(ifstream &fin);
};
 
class employee: public abstr_emp
{
public:
    employee() :abstr_emp() {};
    employee(const string& fn, const string & ln, const string &j) :
        abstr_emp(fn, ln, j) {};
    virtual void ShowAll() const { abstr_emp::ShowAll(); };
    virtual void SetAll() { abstr_emp::SetAll(); };
    virtual bool writeall(ofstream &fout) const;
    virtual bool getall(ifstream &fin) { return abstr_emp::getall(fin); };
};
 
class manager : virtual public abstr_emp
{
private:
    int inchargeof;
protected:
    int InChargeOf() const { return inchargeof; };
    int & InChargeOf() { return inchargeof; };
public:
    manager() :abstr_emp(), inchargeof(0) {};
    manager(const string & fn, const string & ln, const string & j, int ico = 0) :
        abstr_emp(fn, ln, j), inchargeof(ico) {};
    manager(const abstr_emp& e, int ico) : abstr_emp(e), inchargeof(ico) {};
    manager(const manager &m) : abstr_emp(m), inchargeof(m.inchargeof) {};
    virtual void ShowAll() const;
    virtual void SetAll();
    virtual bool writeall(ofstream &fout) const;
    virtual bool getall(ifstream &fin);
};
 
class fink : virtual public abstr_emp
{
private:
    string reportsto;
protected:
    const string ReportsTo() const { return reportsto; };
    string & ReportsTo() { return reportsto; };
public:
    fink() :abstr_emp(), reportsto("No_reprs") {};
    fink(const string & fn, const string & ln, const string & j, const string & rpo) :
        abstr_emp(fn, ln, j), reportsto(rpo) {};
    fink(const abstr_emp & e, const string& rpo) : abstr_emp(e), reportsto(rpo) {};
    fink(const fink & e) : abstr_emp(e), reportsto(e.reportsto) {};
    virtual void ShowAll() const;
    virtual void SetAll();
    virtual bool writeall(ofstream &fout) const;
    virtual bool getall(ifstream &fin);
};
 
class highfink : public manager, public fink
{
public:
    highfink() : manager(), fink() {};
    highfink(const string & fn, const string & ln, const string & j, const string & rpo) :
        manager(fn, ln, j), fink(fn, ln, j, rpo) {};
    highfink(const abstr_emp &e, const string & rpo, int ico) :
        manager(e, ico), fink(e, rpo) {};
    highfink(const fink& f, int ico) :
        manager(f, ico), fink(f) {};
    highfink(const manager & m, const string & rpo) :
        manager(m), fink(m, rpo) {};
    highfink(const highfink & h) : manager(h), fink(h) {};
    virtual void ShowAll() const;
    virtual void SetAll();
    virtual bool writeall(ofstream &fout) const;
    virtual bool getall(ifstream &fin);
};
Тест:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include "Employee.h"
#include <memory>
 
using std::cerr;
using std::ios_base;
using std::fstream;
using std::cout;
using std::endl;
using std::cin;
 
const int MAX = 2;
abstr_emp *pc[MAX];
 
void usr_inp(abstr_emp** pc, int nn);
void show_it(abstr_emp** pc, int nn);
void free(abstr_emp** pc, int nn);
bool save2file(abstr_emp** pc, int nn, ofstream& fout);
bool read_from_file(abstr_emp** pc, int nn, ifstream& fin);
 
int main()
{
    ofstream fout;
    fout.open("f1.txt", ios_base::out | ios_base::app | ios_base::binary);
    if (!fout.is_open())
    {
        cerr << "Error opening " << "f1.txt" << " file!\n";
        exit(EXIT_FAILURE);
    }
    
    fout.seekp(0, fout.end);
    long length = fout.tellp();
    if (length == 0) 
    { 
        usr_inp(pc, MAX);
        cout << "\n\nUr input to be written in a file: ";
        show_it(pc, MAX);
        if (save2file(pc, MAX, fout))
        {
            cout << "Saved successfully...";
        }
                
        fout.close();
    }
    else {
        fout.seekp(0, fout.beg);
        ifstream fin;
        fin.open("f1.txt", ios_base::in | ios_base::binary);
 
        if (!fin.is_open())
        {
            cerr << "Error opening " << "f1.txt" << " file!\n";
            exit(EXIT_FAILURE);
        }
 
        if (read_from_file(pc, MAX, fin))
            show_it(pc, MAX);
        
        fin.clear();
        fin.close();
 
        cout << "Modify info? (Y/N): ";
        char yn;
        while (cin >> yn && tolower(yn) != 'n')
        {
            if (tolower(yn) == 'y')
            {
                free(pc, MAX);
                usr_inp(pc, MAX);
                if (save2file(pc, MAX, fout))
                {
                    cout << "Saved successfully...";
                    break;
                }
            }
            else {
                cout << "Wrong value. Try again pls: ";
                continue;
            }
        }
        cin.get();
    }; 
 
    fout.close();
 
    cout << "Programm terminating...\n";
    free(pc, MAX);
    cin.get();
 
    return 0;
}
 
void usr_inp(abstr_emp** pc, int nn)
{
    int W_class;
    for (int i = 0; i < nn; i++)
    {
        cout << "Type of the worker (0 for Employee, 1 for Manager, 2 for Fink, 3 for HighFink):\n";
        cin >> W_class;
        cin.get();
        switch (W_class){
            case Employee: pc[i] = new employee;
                break;
            case Manager: pc[i] = new manager;
                break;
            case Fink: pc[i] = new fink;
                break;
            case Highfink: pc[i] = new highfink;
                break;
            default: cout << "Ur value has not been matched..\n";
                break;
        };
        pc[i]->SetAll();            
    };
}
 
void show_it(abstr_emp** pc, int nn)
{
    for (int i = 0; i < nn; i++)
        pc[i]->ShowAll();
}
 
void free(abstr_emp** pc, int nn)
{
    for (int i = 0; i < nn; i++)
    {
        delete pc[i];
    };
}
 
bool save2file(abstr_emp** pc, int nn, ofstream& fout)
{
    int i;
    cout << "Saving to the file..\n";
    for (i = 0; i < MAX; i++)
    {
        pc[i]->writeall(fout);
    }
 
    if (!fout)
    {
        cerr << "Smth went wrong while writing into the file..\n";
        system("pause");
        return false;
    }
    else return true;
}
 
bool read_from_file(abstr_emp** pc, int nn, ifstream& fin)
{
    cout << "Reading the info from a file:\n";
    int type;
    int i = 0;
    while (!fin.eof() && i < MAX)
    {
        fin.read((char *)&type, sizeof(type));
        switch (type) {
        case Employee: pc[i] = new employee;
            break;
        case Manager: pc[i] = new manager;
            break;
        case Fink: pc[i] = new fink;
            break;
        case Highfink: pc[i] = new highfink;
            break;
        default: cout << "ID Value has not been matched..\n";
            system("pause");
            break;
        }
 
        pc[i++]->getall(fin);
    }
    if (fin)
        return true;
    else return false;
}
Реализация:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include "Employee.h"
 
using std::cout;
using std::endl;
using std::cin;
 
void abstr_emp::ShowAll() const
{
    cout << "Employee info:\n";
    cout << "Name: " << fname << endl
        <<"Last name: " << lname << endl 
        <<"Job: " << job << endl;
}
void abstr_emp::SetAll()
{
    cout << "Input the name: ";
    getline(cin, fname);
    cout << "Lname: ";
    getline(cin, lname);
    cout << "Job: ";
    getline(cin, job);
}
 
bool abstr_emp::writeall(ofstream & fout) const
{
    fout.write((char*) &fname, sizeof(fname));
    fout.write((char*) &lname, sizeof(lname));
    fout.write((char*) &job, sizeof(job));
    if (fout)
        return true;
    else return false;
}
 
bool abstr_emp::getall(ifstream & fin)
{
    fin.read((char*)&fname, sizeof(fname));
    fin.read((char*)&lname, sizeof(lname));
    fin.read((char*)&job, sizeof(job));
    if (fin)
        return true;
    else return false;
}
 
ostream & operator<<(ostream & os, const abstr_emp & e)
{
    os << "Fname: " << e.fname << endl;
    os << "Lname: " << e.lname << endl;
    os << "Job: " << e.job << endl;
    return os;
}
 
void manager::ShowAll() const
{
    abstr_emp::ShowAll();
    cout << "Inchargeof: " << InChargeOf() << endl;
}
 
void manager::SetAll()
{
    abstr_emp::SetAll();
    cout << "Inchargeof: ";
    cin >> InChargeOf();
}
 
bool manager::writeall(ofstream & fout) const
{
    classType Type = Manager;
    fout.write((char*)&Type, sizeof(Type));
    abstr_emp::writeall(fout);
    fout.write((char*) &inchargeof, sizeof(inchargeof));
    if (fout)
        return true;
    else return false;
}
 
bool manager::getall(ifstream & fin)
{
    abstr_emp::getall(fin);
    fin.read((char *) &inchargeof, sizeof(inchargeof));
    if (fin)
        return true;
    else return false;
}
 
void fink::ShowAll() const
{
    abstr_emp::ShowAll();
    cout << "Reports to: " << ReportsTo() << endl;
}
 
void fink::SetAll()
{
    abstr_emp::SetAll();
    cout << "Reports to: ";
    cin >> ReportsTo();
}
 
bool fink::writeall(ofstream & fout) const
{
    classType Type = Fink;
    fout.write((char*)&Type, sizeof(Type));
    abstr_emp::writeall(fout);
    fout.write((char*)&reportsto, sizeof(reportsto));
    if (fout)
        return true;
    else return false;
}
 
bool fink::getall(ifstream & fin)
{
    abstr_emp::getall(fin);
    fin.read((char *)&reportsto, sizeof(reportsto));
    if (fin)
        return true;
    else return false;
}
 
void highfink::ShowAll() const
{
    cout << "Showing highfink output items: \n";
    abstr_emp::ShowAll();
    cout << "Inchargeof: " << manager::InChargeOf() << endl;
    cout << "Reports to: " << fink::ReportsTo() << endl;
}
 
void highfink::SetAll()
{
    abstr_emp::SetAll();
    cout << "Inchargeof: ";
    cin >> manager::InChargeOf();
    cout << "Reports to: ";
    cin >> fink::ReportsTo();
}
 
bool highfink::writeall(ofstream & fout) const
{
    classType Type = Highfink;
    fout.write((char*)&Type, sizeof(Type));
    abstr_emp::writeall(fout);
    const int ico = InChargeOf();
    const string rpt = ReportsTo();
    fout.write((char*)&ico, sizeof(ico));
    fout.write((char*)&rpt, sizeof(rpt));
    if (fout)
        return true;
    else return false;
}
 
bool highfink::getall(ifstream & fin)
{
    abstr_emp::getall(fin);
    int ico = manager::InChargeOf();
    string rpt = fink::ReportsTo();
    fin.read((char *)&ico, sizeof(ico));
    fin.read((char *)&rpt, sizeof(rpt));
    if (fin)
        return true;
    else return false;
}
 
bool employee::writeall(ofstream & fout) const
{
    classType Type = Employee;
    fout.write((char*)&Type, sizeof(Type));
    return abstr_emp::writeall(fout);
}
Буду признателен за любую помощь!
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.09.2018, 00:36
Ответы с готовыми решениями:

Виртуальные базовые классы
Необходимо написать примеры с комментариями использования виртуальных базовых классов

Виртуальные базовые классы
Есть программа. Нужно сделать с ней виртуальный базовый класс и написать коментарии. #include...

Виртуальные абстрактные базовые классы
Привет всем!:-) Вчера столкнулся со следующей проблемой: компилятор ругается на чистый виртуальный...

Виртуальные базовые классы/закрытое наследование
Хотел уточнить правильно ли я понял материал. Если я породил два класса через виртуальное, открытое...

4
165 / 108 / 57
Регистрация: 30.08.2018
Сообщений: 357
05.09.2018, 01:36 2
У вас ответ в вопросе
Цитата Сообщение от AntonyV Посмотреть сообщение
Причем ошибка возникает с данными, кот были считаны из бинарников.
запись std::string не верна
C++
1
2
3
 fout.write((char*) &fname, sizeof(fname));
    fout.write((char*) &lname, sizeof(lname));
    fout.write((char*) &job, sizeof(job));
sizeof (string) возвращает не длину строки, а размер типа std::string в байтах.

Попробуйте так писать
C++
1
fout.write( fname.c_str(), fname.size());
1
4055 / 3309 / 924
Регистрация: 25.03.2012
Сообщений: 12,451
Записей в блоге: 1
05.09.2018, 02:00 3
Лучший ответ Сообщение было отмечено AntonyV как решение

Решение

C++
1
2
3
    fin.read((char*)&fname, sizeof(fname));
    fin.read((char*)&lname, sizeof(lname));
    fin.read((char*)&job, sizeof(job));
чтение строк неверно. Под них не выделяется память.
(да, это "автоматические строки", к ним нельзя обращаться как к массиву, либо на худой конец перед аписью в них надо выделить память ресайзом)

Добавлено через 17 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
bool abstr_emp::writeall(ofstream & fout) const
{
    size_t sz = fname.size();
    fout.write((char*)&sz, sizeof(sz));
    fout.write(fname.c_str(), sz);
 
    sz = lname.size();
    fout.write((char*)&sz, sizeof(sz));
    fout.write(lname.c_str(), sz);
 
    sz = job.size();
    fout.write((char*)&sz, sizeof(sz));
    fout.write(job.c_str(), sz);
 
    if (fout)
        return true;
    else return false;
}
bool abstr_emp::getall(ifstream & fin)
{
    size_t sz;
    fin.read((char*)&sz, sizeof(sz));
    fname.resize(sz);
    fin.read(&fname[0], sz);
 
    fin.read((char*)&sz, sizeof(sz));
    lname.resize(sz);
    fin.read(&lname[0], sz);
 
    fin.read((char*)&sz, sizeof(sz));
    job.resize(sz);
    fin.read(&job[0], sz);
    if (fin)
        return true;
    else return false;
}
 
bool fink::writeall(ofstream & fout) const
{
    classType Type = Fink;
    fout.write((char*)&Type, sizeof(Type));
    abstr_emp::writeall(fout);
    size_t sz = reportsto.size();
    fout.write((char*)&sz, sizeof(sz));
    fout.write(reportsto.c_str(), sz);
    if (fout)
        return true;
    else return false;
}
bool fink::getall(ifstream & fin)
{
    abstr_emp::getall(fin);
    size_t sz;
    fin.read((char*)&sz, sizeof(sz));
    reportsto.resize(sz);
    fin.read(&reportsto[0], sz);
    if (fin)
        return true;
    else return false;
}
1
0 / 0 / 0
Регистрация: 02.03.2013
Сообщений: 51
05.09.2018, 11:28  [ТС] 4
JaponDemon, Kuzia domovenok, спасибо! Думал записывать и читать объект string именно как объект - чтобы в бинарнике поле выделялось под него наверняка и не надо было писать дополнительно размер строки для чтения. Например, как бы вы записывали свой созданный объект?
Kuzia domovenok, полагал что объект string при записи из бинарника расширяется автоматически, это же динамический контейнер. Kuzia domovenok, глупый вопрос: вы пишете
C++
1
&job[0]
, а не
C++
1
(char*)&job
Они эквивалентны?
0
18472 / 9629 / 2356
Регистрация: 30.01.2014
Сообщений: 16,882
05.09.2018, 12:03 5
Цитата Сообщение от AntonyV Посмотреть сообщение
Они эквивалентны?
Нет.
Цитата Сообщение от AntonyV Посмотреть сообщение
полагал что объект string при записи из бинарника расширяется автоматически
На основании какой информации он мог бы это делать?
Тем более, что у вас в функции read\write передаются указатели на char. Следовательно даже гипотетическая возможность что-то учесть автоматически теряется, т.к. теряется информация о типе.
Магия только в сказках.
0
05.09.2018, 12:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.09.2018, 12:03
Помогаю со студенческими работами здесь

Виртуальные базовые классы: какие требования предъявляются к иерархии наследования?
класс на вершине иерархии определяет конструктор с параметрами. какие требования предъявляются к...

Виртуальные деструкторы
#include &lt;iostream&gt; using namespace std; class first { public: first(); virtual...

Виртуальные деструкторы
Можно ли вызвать деструктор базового класса вместо использования виртуальных деструкторов? class...

Наследование. Виртуальные методы/деструкторы.
Есть базовый класс Cell (код можно даже не смотреть - он просто для иллюстрации -&gt; вопрос внизу)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru