Очень простая сериализация для 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. Обеспечение удобства функции для программиста