Есть 2 класса, один наследуется от другого, причем базовый класс содержит хотя бы 1 виртуальный метод.
При первом запуске программы я записываю в файл в бинарном виде экземпляр наследуемого класса и при повторном запуске программы я пытаюсь считать из файла обратно в объект. Если не использовать полиморфизм, то есть не создавать виртуальные функции в базовом классе, то все работает нормально, в другом случае программа крашится, пишет obj-> было 0x..... ,посмотрев в отладчике я заметил что чтение памяти из _vfptr невозможно, вот и задаюсь вопросом, как это можно обойти.
class B {
public:
B() {}
float f;
virtual void printf() = 0;
};
class A : public B {
public:
int a;
char k;
A() {
f = 2;
a = 1111;
k = '?';
}
void printf() {
cout << a << endl << k << endl << f << endl << endl;
}
};
int main() {
A *obj = new A();
FILE* file;
int t = 1;//(после 1 запуска программы меняю значение на 2 и повторно запускаю)
if (t == 1) {
file = fopen("file.dat", "w+b");
fwrite(obj, sizeof(obj), 1, file);
fclose(file);
}
else if (t == 2) {
file = fopen("file.dat", "r+b");
fread(obj, sizeof(obj), 1, file);
fclose(file);
obj->printf();
}
}
Прямая запись нетривиальных объектов в бинарный файл как "сырых" бинарных данных возможна только в контексте одной программной сессии. Т.е. фактически такой подход жизнеспособен только если вы реализуете некое подобие своего собственного временного "своп файла".
Пытаться использовать такой способ сохранения данных между программными сессиями ("при повторном запуске программы...") обречены на провал.
Чтобы выполнить сохранение, живущее между программными сессиями, вам придется самостоятельно разработать некий формат/протокол (возможно, весьма нетривиальный), который позволит вам сериализовать те свойства ваших данных, которые впрямую в файл записать нельзя: значения указателей, типы полиморфных объектов и т.д. и т.п.
Вещи, которые не являются plain old data, нельзя просто писать на диск и считывать как единое целое. Даже если внутри класса нет указателей на какие-то данные, у вас есть указатель на таблицу виртуальных функций. Пока вы в пределах одного выполнения, указатели еще сохраняются, так что возможно чтение-запись, но в разных...
Заведите функции записи и чтения членов-данных, а не всего объекта в целом.
Вот тут, тут или тут я уже отвечал на подобные вопросы, можете посмотреть.
Вот вам код, как это делать правильно.
class B {
public:
B() {}
float f;
virtual void printf() = 0;
virtual void write(FILE* fl)
{
fwrite(&f,sizeof(f),1,fl);
}
virtual void read(FILE* fl)
{
fread(&f,sizeof(f),1,fl);
}
};
class A : public B {
public:
int a;
char k;
A() {
f = 2;
a = 1111;
k = '?';
}
void printf() {
cout << a << endl << k << endl << f << endl << endl;
}
virtual void write(FILE* fl)
{
B::write(fl);
fwrite(&a,sizeof(a),1,fl);
fwrite(&k,sizeof(k),1,fl);
}
virtual void read(FILE* fl)
{
B::read(fl);
fread(&a,sizeof(a),1,fl);
fread(&k,sizeof(k),1,fl);
}
};
int main() {
A *obj = new A();
FILE* file;
int t = 1;//(после 1 запуска программы меняю значение на 2 и повторно запускаю)
if (t == 1) {
file = fopen("file.dat", "w+b");
obj->write(file);
fclose(file);
}
else if (t == 2) {
file = fopen("file.dat", "r+b");
obj->read(file);
fclose(file);
obj->printf();
}
}
Как любитель нестандартных выстрелов в ногу я не мог пройти мимо. Рабочее решение найти удалось, вот кусок кода:
int main()
{
A *obj = new A();
FILE* file;
int t = 2;//(после 1 запуска программы меняю значение на 2 и повторно запускаю)
if (t == 1)
{
file = fopen("file.dat", "w+b");
// Обратите внимание, в оригинале у вас тут написано sizeof(obj), но obj - это указатель, а его размер всегда 4 (или 8) байт
// надо писать либо sizeof(A) либо sizeof(*obj), чтобы получить реальный размер занятой памяти
fwrite(obj, sizeof(A), 1, file);
fclose(file);
}
else if (t == 2)
{
A* donor = new A(); // Донор нам нужен для копирования __vfptr
A* obj2 = new A(); // Объект, куда читаем из файла
A* obj3 = new A(); // Объект, который будет создан по данным, считанным из файла
memset(obj2, 0, sizeof(A)); // Для чистоты эксперимента вся память зануляется
memset(obj3, 0, sizeof(A));
// Читаем из файла в obj2
file = fopen("file.dat", "r+b");
fread(obj2, sizeof(A), 1, file);
fclose(file);
// После чтения из файла мы получили obj2 с невалидным __vfptr, копируем целиком всю память в obj3
memcpy(obj3, obj2, sizeof(A));
// Копируем для obj3 валидный __vfptr из экземпляра-донора
memcpy(obj3, donor, sizeof(void*));
// И оно работает (по крайней мере у меня)
obj3->printf();
}
getchar();
return 0;
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Есть строка: Я уже 15 года занимаюсь программированием, написал 10
Сейчас мне нужно напечатать свою страницу (в pdf или на бумагу)Для этого я использую это: window
Как нарисовать такой треугольник на JavaScript?
Есть таблица, которая создается динамически от JSON, это значит, что нет постоянных столбцов и значения могут быть разными(числа, строки), помогите,...