Форум программистов, компьютерный форум CyberForum.ru

Считывание класса с виртуальным наследованием из бинарного файла - C++

Восстановить пароль Регистрация
 
Riderik
 Аватар для Riderik
28 / 28 / 1
Регистрация: 24.07.2011
Сообщений: 171
28.03.2012, 17:33     Считывание класса с виртуальным наследованием из бинарного файла #1
Рассмотрим простой пример. Допустим есть класс А, и производный от него класс В. Наследование виртуальное (обязательно). Создадим объект класса В и запишем в бинарный файл. Сразу же считаем, выводим на экран - всё работает. Выходим из программы, снова заходим, считываем, пытаемся вывести на экран и получаем ошибку. Без виртуального наследования (с обыкновенным наследованием) ошибки не возникает. Ошибка на скринах. Код программы-примера:

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
#include <iostream>
#include <fstream>
#include <conio.h>
 
using namespace std;
 
class A
{
protected:
    int a;
public:
    A(int _a): a(_a) {}
};
 
 
class B: public virtual A
{
    int b;
public:
    B(int _a, int _b): A(_a), b(_b) {}
    void Show()
    {
        cout<<a<<" "<<b;
    }
};
    
int main()
{
    fstream iof("file",ios::in | ios::out | ios::binary);
    if( !iof.is_open() )
    {
        iof.clear();
        iof.open("file",ios::in | ios::out | ios::binary | ios::trunc);
    }
    
    B obj(1,1);
    char choice;
    while(true)
    {
        cout<<"\n1)Write"
            <<"\n2)Read"
            <<"\n3)Exit";
        choice=_getch();
        switch(choice)
        {
        case '1':
            iof.seekp(0,ios::end);
            iof.write(reinterpret_cast<char*>(&obj), sizeof(obj));
            break;
        case '2':
            iof.read(reinterpret_cast<char*>(&obj),sizeof(obj));
            cout<<"\nis Read: ";
            obj.Show();
            break;
        case '3':
            return 0;
        }
    }
}
Последовательность действий для получения ошибки:
1)Запускаем прогу
2)Выбираем 1 - Write
3)Выходим 3 - exit
4)Запускаем прогу
5)Выбираем 2 - Read

Кстати класс с виртуальным наследованием почему-то на 4 байта тяжелее, чем без него.
Может кто знает как исправить ошибку не убирая виртуальное наследование?
Миниатюры
Считывание класса с виртуальным наследованием из бинарного файла   Считывание класса с виртуальным наследованием из бинарного файла  
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.03.2012, 17:33     Считывание класса с виртуальным наследованием из бинарного файла
Посмотрите здесь:

Считывание данных из бинарного файла C++
Считывание из бинарного файла в массив_не работает! C++
C++ Считывание из бинарного файла и занисение в список
Считывание строки из бинарного файла в string C++
Запись и считывание из бинарного файла C++
Считывание бинарного файла C++
Считывание структуры из бинарного файла C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
silent_1991
Эксперт C++
4945 / 3021 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
29.03.2012, 02:43     Считывание класса с виртуальным наследованием из бинарного файла #2
Как отработает такая функция main (в debug- и в release-конфигурации)?
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
int main()
{
    fstream iof("file",ios::binary);
    if( !iof.is_open() )
    {
        iof.clear();
        iof.open("file",ios::binary);
    }
 
    B obj(1,1);
    char choice;
    while(true)
    {
        cout<<"\n1)Write"
            <<"\n2)Read"
            <<"\n3)Exit";
        choice=_getch();
        switch(choice)
        {
        case '1':
            iof.write(reinterpret_cast<char*>(&obj), sizeof(obj));
            break;
        case '2':
            iof.read(reinterpret_cast<char*>(&obj),sizeof(obj));
            cout<<"\nis Read: ";
            obj.Show();
            break;
        case '3':
            return 0;
        }
    }
}
Riderik
 Аватар для Riderik
28 / 28 / 1
Регистрация: 24.07.2011
Сообщений: 171
29.03.2012, 02:51  [ТС]     Считывание класса с виртуальным наследованием из бинарного файла #3
silent_1991, не считывает и не записывает
silent_1991
Эксперт C++
4945 / 3021 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
29.03.2012, 02:55     Считывание класса с виртуальным наследованием из бинарного файла #4
Riderik, странно, у меня ваш код в студии не считывал и не записывал. Правда в gcc как ваш, так и мой вариант отработал, причём как в одном сеансе записи, так и в разных. В студии мой вариант и в дебаге, и в релизе отработал. У меня есть вариант объяснения проблемы, но есть в нём небольшие нестыковки, да и проблему как таковую мне воспроизвести не удалось.
Riderik
 Аватар для Riderik
28 / 28 / 1
Регистрация: 24.07.2011
Сообщений: 171
29.03.2012, 03:02  [ТС]     Считывание класса с виртуальным наследованием из бинарного файла #5
Ну я пока что узнал, что это не POD класс, а значит он в памяти расположен не в одном месте, а может ссылаться на другие области и поэтому его нельзя писать и читать обычными write и read
silent_1991
Эксперт C++
4945 / 3021 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
29.03.2012, 03:30     Считывание класса с виртуальным наследованием из бинарного файла #6
Цитата Сообщение от Riderik Посмотреть сообщение
это не POD класс
Да, именно на этом основывается моё предположение.
Цитата Сообщение от Riderik Посмотреть сообщение
он в памяти расположен не в одном месте
Суть не в этом, а в том, что для не POD-типа нельзя делать предположений о том, как он располагается в памяти. Об этом ниже.
В объектах класса, который виртуально наследует базовый класс, располагается специальный указатель на таблицу виртуальных классов (именно классов, не функций). Эта таблица содержит константные смещения, которые помогают добраться до той области памяти внутри объекта данного класса, которая содержит подобъект базового класса (ведь все данные в иерархии хотя и структурированы, в памяти лежат последовательно в пределах объекта). Так вот, моя идея в том, что когда запись объекта в файл и чтение его из файла происходят в пределах одного сеанса, то мы сначала записываем данные (в том числе и указатель на таблицу виртуальных классов!) в файл, а потом тут же читаем данные (в том числе и указатель на таблицу виртуальных классов!) обратно в объект. Понятно, что в пределах одного сеанса таблица размещается в одной и той же области памяти, и записав адрес в файл и тут же считав его обратно, мы ничего не испортим. Однако если мы записали адрес в одном сеансе и считали в другом, то никто не гарантирует, что адреса эти будут совпадать (с другой стороны, по идее-то гарантирует, но об этом ниже). Поэтому при чтении файла в новом сеансе мы считываем адрес, который может быть совершенно левым, обращаемся в память по этому адресу и получаем по башке от системы, которая нас в эту память пускать категорически отказывается.
Однако нестыковка здесь вот в чём. Вся информация о таблице виртуальных классов известна уже на стадии компиляции. Значит, эту таблицу можно разместить статически (что обычно и делается). Значит, в пределах программы у неё всегда будет фиксированный адрес. Значит, нет никаких проблем сохранить этот адрес в одном сеансе, а считать в другом, адреса должны быть одинаковы. Что и показывает моя попытка воспроизвести вашу ошибку (вернее, неудача этой попытки). Получается, что это особенность именно вашего компилятора, или я что-то упустил или где-то ошибся...

Добавлено через 2 минуты
Но, как бы то ни было, нельзя так сериализовать объекты, строение которых не оговорено стандартом, потому как всё, что не оговорено, лежит на совести разработчиков компилятора, и реализация виртуального наследования может быть такой, как я описал, а может быть совершенно иной.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.03.2012, 12:49     Считывание класса с виртуальным наследованием из бинарного файла
Еще ссылки по теме:

Считывание из бинарного файла и запись данных в две строковых переменные C++
Считывание бинарного файла C++
Сформировать набор классов связанных между собой виртуальным наследованием,описать каждый класс C++
C++ Считывание из бинарного файла
Считывание из бинарного файла в структуру с последующим выводом C++

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

Или воспользуйтесь поиском по форуму:
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7954 / 4716 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
29.03.2012, 12:49     Считывание класса с виртуальным наследованием из бинарного файла #7
Вывод просто. Юзайте boost::serialization.
Yandex
Объявления
29.03.2012, 12:49     Считывание класса с виртуальным наследованием из бинарного файла
Ответ Создать тему
Опции темы

Текущее время: 11:05. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru