в любом случае, чтобы восстановить некоторые сохраненные классы из их Vtable? - PullRequest
4 голосов
/ 22 июня 2011

Я копирую некоторые объекты в файл, и все они получены из одного класса.но я хочу иметь возможность вызывать их функции после загрузки, чтобы делать то, что должен делать этот класс, вот что я делал до сих пор:

#include <iostream>
#include <fstream>

using namespace std;

struct a
{
    virtual void print()
    {
        cout << "this is a.\n";
    };
};

struct b : public a
{
    virtual void print()
    {
        cout << "this is b.\n";
    }
};

int main()
{
    ofstream testofile("test.bin",ios::binary);
    a* tempa = new a;
    a* tempb = new b;
    testofile.write((char*)tempa,sizeof(a));
    testofile.write((char*)tempb,sizeof(b));
    testofile.flush();
    testofile.close();
    ifstream testifile("test.bin",ios::binary);
    a* x = (a*)new char[max(sizeof(a),sizeof(b))];
    testifile.read((char*)x,sizeof(a));
    x->print();
    testifile.read((char*)x,sizeof(b));
    x->print();
}

мой пример работает нормально, но если я комментирую сохранить часть, а затем выполнитьпрограмма, кажется, vtable является недопустимым для нового запущенного приложения (хотя в моем коде ничего не изменилось).проблема в том, что мой класс файлового менеджера не знает обо всех возможных объектах, которые могут извлекаться из моего базового объекта, и я хочу перестроить всю структуру моего приложения, используя только один вызов файлового менеджера для его загрузки.конечно, каждый из моих объектов имеет свои собственные функции сохранения / загрузки, но как файловому менеджеру угадать, где функция загрузки подходит для текущего блока данных?

Ответы [ 3 ]

7 голосов
/ 22 июня 2011

Пожалуйста, не делай этого.Никогда.

По сути, вы используете приведение в старом стиле для приведения a* к char*.В результате без вывода сообщений reinterpret_cast между двумя несвязанными типами и сильно зависит от реализации .Вы не можете полагаться на базовый макет памяти: он может измениться по любой причине (даже при использовании того же компилятора).

Если ваш класс содержит указатели, у вас нет гарантии, что данные, на которые они указывают, все еще будут там.(или просто то же самое) при перезагрузке вашего класса.

Если вы хотите обеспечить механизм сериализации , создайте свои собственные функции serialize() и deserialize() (они могут быть даже шаблоннымифункции, которые вы можете затем специализировать, или просто обычные функции-члены, это не имеет значения).

Конечно, это требует немного больше работы, но ради надежности.Более того, вы можете оптимизировать представление данных под любой тип хранилища (сохраненный на диск, отправленный в сеть и т. Д.) И даже изменить интерфейс вашего класса и при этом сохранить совместимость с уже сериализованными экземплярами.

1 голос
/ 22 июня 2011

Код, который вы пишете, не будет переносимым (endianess).

Поскольку примерное смещение таблицы виртуальных функций базового класса или структуры может измениться.Компилятор Solaris и Aix помещают vft в конец struct / class и VC ++ в смещение (0) в случае одиночного наследования.Я никогда не проверяю с помощью g ++, но возможны некоторые забавы.

Я не рекомендую прямую запись объекта, если у вас нет большого количества данных и вам не нужно поддерживать эти данные в течение длительного времени (то есть временных данных).

Значение vft зависит от того, где ваша динамическая библиотека (dll или около того) отображается в виртуальной памяти.Если вы напишите свой собственный распределитель и исправите vft, он может работать.Но это довольно худой.

0 голосов
/ 22 июня 2011

Требуется механизм сериализации, при котором ваш производный вызов метода сериализации сериализуется на базе, а затем сериализует сначала некоторый идентификатор, чтобы указать производный тип (typeid), а затем его собственных членов.фабричный объект, который читает файл и определяет тип (из производного сериализованного typeid), устанавливает объект этого типа и вызывает метод deserailize объекта, чтобы загрузить его из файла и вернуть объект через указатель базового класса.1002 *

...