Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Чтение/запись объектов разных классов в бинарник 
:(
    Опции темы
moskitos80
  Дата 17.8.2012, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 17.8.2012

Репутация: нет
Всего: нет



Здравствуйте. Изучаю С++ по Лафоре. Дошёл до места, где объясняется, как записывать объекты разных классов в один бинарник.

У Лафоре, идея чтения из одного файла, данных объектов разных классов, следующая: перед записью данных объекта записываем его тип, а при чтении - сначала читаем тип, создаём объект нужного класса и читаем в него данные. Там же кстати приводится рабочий(!) пример этого действа.

Почитал тему - понял - начал делать самостоятельно: облом, прога вылетает с ошибкой сегментации памяти. В чём дело не могу понять - хоть убейте! Который день ломаю голову. 

Описание проблемы следующее - есть Базовый класс: Person, и есть 2 его наследника: Student и Employee, а так же есть класс Storage, который должен их сохранять и читать из файла. Так вот, если прога (листинг снизу) отрабатывает одним запуском, т.е. пишет в файл, а потом сразу читает - всё ок! НО, если, закоментировать storage.readAll(); и таким образом сначала только записать данные, а потом  закоментировав логику записи, попытаться прочитать записанное, то прога вылетает с ошибкой сегментации. 

Про POD объекты я немного почитал пока использовал поиск по этому вопросу, и что смущает, так это то что у Лафоре в примере (рабочем!) присутствует и наследование и приватные поля... короче признаки не POD объектов - и всё прекрасно работает без сериализации и boost! 

В общем дошёл я до того, что начал делать дампы памяти объектов программы, а заодно открыл HEX-редактором получающийся бинарник. И заметил я, что когда в методе storage.readAll() - инициализируется нужный обект: pers1[cnt] = new Student; (я указал в коде) он имеет отличающийся набор байтов от того, который в него считыватся из файла. При этом отличается только первый байт данных объекта! И почему-то всегда на 20(HEX)! Повторюсь, что при запуске программы на чтение и на запись данные при инициализации и те, что в файле абсолютно идентичны. 

Люди знает кто нибудь что это за фича? Подскажите, скоро дураком стану.  smile 

Листинг:

Код

#include <iostream>
#include <fstream>
#include <typeinfo>
 
using namespace std;
 
const int MAX_PERS = 4;
const char* PERS_FILE_NAME = "PERS_DATA.ART";
 
// Типы данных объектов:
enum Ctypes {
    Tstudent,
    Temployee
}; 
/////////////////////////////////////////////////////////////////////////////////
class Person
{
    public :
        Person() {
            this->age = 500;
        }
        virtual void getData(void)
        {
            cout  << endl << "Age  " << this->age  << endl;
        }
    protected :
        int age;
};
/////////////////////////////////////////////////////////////////////////////////
class Student : public Person
{
    public :
        Student() : Person(), gpa (13.6), course (8) {}
 
        void getData(void)
        {
            cout << endl << "---------- Student data: ----------" << endl;
            Person::getData();
            cout << endl << "GPA "     << this->gpa
                 << endl << "Course  " << this->course  << endl;
        }
    protected :
        float gpa;
        int course;
};
/////////////////////////////////////////////////////////////////////////////////
class Employee : public Person
{
    public :
        Employee() : Person(), post (555) {}
 
        void getData(void)
        {
            cout << endl << "---------- Employee data: ----------" << endl;
            Person::getData();
            cout << endl << "Post "     << this->post << endl;
        }
    protected :
        int post;
};
/////////////////////////////////////////////////////////////////////////////////
class Storage
{
    public :
        // Сохранить
        bool store(Person** pers1, int cnt)
        {
            Ctypes type;
            int size = 0;
 
            ofstream outf(PERS_FILE_NAME, ios::binary|ios::app);
            if (!outf) {cerr << endl << "Err open!"; return false;}
 
            for(int i = 0; i < cnt; i++) {
 
                type = this->getType(pers1[i]);
                outf.write((char*)&type, sizeof(type));
                if (!outf) {cerr << endl << "Err write type!"; return false;}
 
                if (type == Tstudent) {
                    size = sizeof(Student);
                } else {
                    size = sizeof(Employee);
                }
 
                outf.write((char*)pers1[i], size);
                if (!outf) {cerr << endl << "Err write type!"; return false;}
            }
            return true;
        }
        // Прочитать
        bool readAll()
        {
            Person* pers1[MAX_PERS];
 
            int size = 0, cnt = 0;
            Ctypes type;
 
            ifstream inf(PERS_FILE_NAME, ios::binary);
            if (!inf) {cerr << endl << "Err open!"; return false;}
 
            while (1) {
                inf.read((char*)&type, sizeof(type));
                if(inf.eof()) {break;}
 
                if (type == Tstudent) {
                    // Инициализация 
                    pers1[cnt] = new Student; // дамп: 28 2c 47 00 f4 01 00 00|9a 99 59 41 08 00 00 00
                    size = sizeof(Student);
                } else {
                    // Инициализация 
                    pers1[cnt] = new Employee; 
                    size = sizeof(Employee);
                }
                // Считывается из файла: 48 2c 47 00 f4 01 00 00|9a 99 59 41 08 00 00 00
                inf.read((char*)pers1[cnt], size); 
                if (!inf) {cerr << endl << "Err read type!"; return false;}
                pers1[cnt++]->getData();
            }
            return true;
        }
        // Получить тип объекта
        Ctypes getType(Person* person)
        {
            if (typeid(*person) == typeid(Student)) {
                return Tstudent;
            }
            return Temployee;
        }
};
/////////////////////////////////////////////////////////////////////////////////
 
int main()
{
    Storage storage;

    // ---------------------------------   Логика записи:
    Person* pers[MAX_PERS];
 
    // Инициализируем массив
    for (int i = 0; i < MAX_PERS; i++) {
        pers[i] = NULL;
    }
    // Тупо ручками:
    pers[0] = new Student;
    pers[1] = new Student;
    pers[2] = new Employee;
    pers[3] = new Employee;
 
    // Пишем
    if (storage.store(pers, MAX_PERS)) {
        cout << endl << "STORED OK" << endl;
    }
    //---------------------------------------------------------

    // Читаем
    storage.readAll();
 
    return 0;
}

PM MAIL   Вверх
leniviy
Дата 17.8.2012, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 552
Регистрация: 8.2.2003
Где: Спб

Репутация: нет
Всего: 5



Это потому, что когда ты коментируешь часть кода, меняется положение таблицы виртуальных функций в памяти, а первые 4 байта объекта - это указатель на неё.
Нельзя просто так взять и прочитать из файла объекты с виртуальными функциями.

Это сообщение отредактировал(а) leniviy - 17.8.2012, 18:53
PM MAIL   Вверх
moskitos80
Дата 17.8.2012, 19:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 17.8.2012

Репутация: нет
Всего: нет



Цитата(leniviy @ 17.8.2012,  18:50)
Это потому, что когда ты коментируешь часть кода, меняется положение таблицы виртуальных функций в памяти, а первые 4 байта объекта - это указатель на неё.
Нельзя просто так взять и прочитать из файла объекты с виртуальными функциями.

Ох leniviy - спасибо попробую сделать так что бы не комментировать код.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0665 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.