Очень простая сериализация для C++ - Пример очень простой сериализации

ОГЛАВЛЕНИЕ

Пример очень простой сериализации

Начнем с простого примера. C0 – корневой класс, подлежащий сериализации. Ниже приведена очень простая встроенная реализация.

// главный заголовочный файл
#include "ess_stream.h"
// используйте этот заголовок для хранилища XML
#include "ess_xml.h"
class C0
{
    // следовательно, можно отличить
    short m_id;
    // вектор указателей на C0
    std::vector<C0*> m_children;
    // здесь функция сериализации -
    // она симметрична, работает для чтения и записи
    virtual void serialize(ess::archive_adapter& adapter)
    {
        ESS_STREAM(adapter,m_id);
        ESS_STREAM(adapter,m_children);
    }
public:
    // задается корень наследования
    ESS_ROOT(C0)
    // устанавливается RTTI
    ESS_RTTI(C0,C0)
};

class C1: public C0
{
    // для примера – настоящий класс,
    // вероятно, имел бы больше кода
    ESS_RTTI(C1,C0)
};

ниже приведен код для выполнения сериализации в обоих направлениях:

int version = 1;
std::string xml_root = "root";
std::string instance_name = "x";
// всегда используйте блоки попытка-перехват, так как любые проблемы используют throw()
try
{
    // регистрируется класс
    ess::Registry registry;
    // разновидность с макросом для краткости, орфографических ошибок нет
    registry << ESS_REGISTER(C0,C0);

    // где хранятся данные...
    ess::xml_medium storage;
    {
        // экземпляр для сериализации
        C0 c0;
        C1 c1;
        // эта версия скрывает парсер XML...
        ess::xml_storing_adapter adapter(the_storage,xml_root,version);
        // сохранить корневой C0
        ess::stream(adapter,c0,"c0");
        // сохранить производный C1
        ess::stream(adapter,c1,"c1");
    }
    // десериализовать в p0
    {
        //
        C0* p0 = 0;
        // восстановить из хранилища XML
        Chordia::xml_source xmls(storage.c_str(),storage.size());
        // и адаптер
        ess::xml_loading_adapter adapter(xmls,xml_root,version);
        // направить в указатель C0...
        ess::stream(adapter,p0,instance_name);
        // теперь p0 готов к использованию ...
        delete p0;
    }
}
catch(...)
{
}

XML, сгенерированный в example(), выглядит так:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<root version="1"/>
<class derived_type="C0" name="c0">
    <signed_short name="m_id" value="1"/>
    <vector name="m_children" count="0">
    </vector>
</class>
<class derived_type="C1" name="c1">
    <signed_short name="m_id" value="1"/>
    <vector name="m_children" count="0">
    </vector>
</class>
</root>

Подробно

•    RTTI(информация о типе времени исполнения)
•    Регистрация
•    Адаптеры
•    Обработка ошибок
•    Блочные тесты

Перейдем к деталям. Сохранить базовые классы C++ не слишком трудно - MFC испокон веков имел механизм для осуществления этого. Начнем аналогичным образом; основой системы является сериализация путем разбиения – классы сводятся к мельчайшим элементам, которые затем записываются и считываются во время выполнения. Чтение и запись использует симметричную функцию serialize(), уменьшающую требования к программированию и возможные ошибки. По-настоящему хитрые куски исходят из следующего:

1.    Нет общего базового класса
2.    Правильное восстановление указателей на экземпляры полиморфных классов
3.    Обеспечение удобства функции для компилятора
4.    Обеспечение удобства функции для программиста