Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
 Аватар для Riderik
28 / 28 / 4
Регистрация: 24.07.2011
Сообщений: 171

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

28.03.2012, 17:33. Показов 1969. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Рассмотрим простой пример. Допустим есть класс А, и производный от него класс В. Наследование виртуальное (обязательно). Создадим объект класса В и запишем в бинарный файл. Сразу же считаем, выводим на экран - всё работает. Выходим из программы, снова заходим, считываем, пытаемся вывести на экран и получаем ошибку. Без виртуального наследования (с обыкновенным наследованием) ошибки не возникает. Ошибка на скринах. Код программы-примера:

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 байта тяжелее, чем без него.
Может кто знает как исправить ошибку не убирая виртуальное наследование?
Миниатюры
Считывание класса с виртуальным наследованием из бинарного файла   Считывание класса с виртуальным наследованием из бинарного файла  
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
28.03.2012, 17:33
Ответы с готовыми решениями:

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

Считывание бинарного файла
Здравствуйте, Помогите пожалуйста найти проблему, мне нужно вначале записать текст в бинарный файл а затем считать его, записывает...

Считывание бинарного файла
Здравствуйте! Изначально нужно было прочитать почисленно текстовый файл и забить его в массив. Но т.к. это не получилось, решил прочитать...

6
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
29.03.2012, 02:43
Как отработает такая функция 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;
        }
    }
}
0
 Аватар для Riderik
28 / 28 / 4
Регистрация: 24.07.2011
Сообщений: 171
29.03.2012, 02:51  [ТС]
silent_1991, не считывает и не записывает
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
29.03.2012, 02:55
Riderik, странно, у меня ваш код в студии не считывал и не записывал. Правда в gcc как ваш, так и мой вариант отработал, причём как в одном сеансе записи, так и в разных. В студии мой вариант и в дебаге, и в релизе отработал. У меня есть вариант объяснения проблемы, но есть в нём небольшие нестыковки, да и проблему как таковую мне воспроизвести не удалось.
0
 Аватар для Riderik
28 / 28 / 4
Регистрация: 24.07.2011
Сообщений: 171
29.03.2012, 03:02  [ТС]
Ну я пока что узнал, что это не POD класс, а значит он в памяти расположен не в одном месте, а может ссылаться на другие области и поэтому его нельзя писать и читать обычными write и read
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
29.03.2012, 03:30
Цитата Сообщение от Riderik Посмотреть сообщение
это не POD класс
Да, именно на этом основывается моё предположение.
Цитата Сообщение от Riderik Посмотреть сообщение
он в памяти расположен не в одном месте
Суть не в этом, а в том, что для не POD-типа нельзя делать предположений о том, как он располагается в памяти. Об этом ниже.
В объектах класса, который виртуально наследует базовый класс, располагается специальный указатель на таблицу виртуальных классов (именно классов, не функций). Эта таблица содержит константные смещения, которые помогают добраться до той области памяти внутри объекта данного класса, которая содержит подобъект базового класса (ведь все данные в иерархии хотя и структурированы, в памяти лежат последовательно в пределах объекта). Так вот, моя идея в том, что когда запись объекта в файл и чтение его из файла происходят в пределах одного сеанса, то мы сначала записываем данные (в том числе и указатель на таблицу виртуальных классов!) в файл, а потом тут же читаем данные (в том числе и указатель на таблицу виртуальных классов!) обратно в объект. Понятно, что в пределах одного сеанса таблица размещается в одной и той же области памяти, и записав адрес в файл и тут же считав его обратно, мы ничего не испортим. Однако если мы записали адрес в одном сеансе и считали в другом, то никто не гарантирует, что адреса эти будут совпадать (с другой стороны, по идее-то гарантирует, но об этом ниже). Поэтому при чтении файла в новом сеансе мы считываем адрес, который может быть совершенно левым, обращаемся в память по этому адресу и получаем по башке от системы, которая нас в эту память пускать категорически отказывается.
Однако нестыковка здесь вот в чём. Вся информация о таблице виртуальных классов известна уже на стадии компиляции. Значит, эту таблицу можно разместить статически (что обычно и делается). Значит, в пределах программы у неё всегда будет фиксированный адрес. Значит, нет никаких проблем сохранить этот адрес в одном сеансе, а считать в другом, адреса должны быть одинаковы. Что и показывает моя попытка воспроизвести вашу ошибку (вернее, неудача этой попытки). Получается, что это особенность именно вашего компилятора, или я что-то упустил или где-то ошибся...

Добавлено через 2 минуты
Но, как бы то ни было, нельзя так сериализовать объекты, строение которых не оговорено стандартом, потому как всё, что не оговорено, лежит на совести разработчиков компилятора, и реализация виртуального наследования может быть такой, как я описал, а может быть совершенно иной.
2
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
29.03.2012, 12:49
Вывод просто. Юзайте boost::serialization.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
29.03.2012, 12:49
Помогаю со студенческими работами здесь

Считывание из бинарного файла
СЧИТАТЬ ИЗ БИНАРНОГО ФАЙЛА ВСЕ ВЕЩЕСТВЕННЫЕ ЧИСЛА В МАССИВ И ВЫВЕСТИ ЕГО НА ЭКРАН. #include &lt;iostream&gt; #include &lt;fstream&gt; ...

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

Запись и считывание из бинарного файла
Допустим я реализовываю АТД - контейнер. Там будет функция обновления (Все данные скопировать в файл на жестком дискке, а потом обратно)....

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

Считывание строки из бинарного файла в string
Привет всем!! Помогите новичку понять почему происходит ошибка при считывании строки из файла. void LoadFile() { string j; ...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка SDL3 и Box2D из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru