Очень простая сериализация для C++
ОГЛАВЛЕНИЕ
В данной статье описана реализация легкого механизма для сохранения объектов C++ в XML или двоичные форматы.
• Скачать исходники с файлами проекта для VS2003 - 31.6 Кб
• Скачать исходники с файлами проекта для VS2008 - 31.6 Кб
• Скачать исходники и двоичный файл выпуска - 313 Кб (содержит демонстрационный проект GUI(графический пользовательский интерфейс) для VS2003)
Введение
В данной статье описана реализация легкого механизма для сохранения объектов C++ в XML или двоичные форматы. Статьи такого рода обычно не порождают много графического содержимого, отсюда много вставленных фрагментов кода.
Пример кода содержит проекты VS2003 и VS2008, формирующие консольное приложение для блочного теста. /W4 используется везде.
Кроме того, есть очень простое приложение MFC Контакты, отображающее содержимое в гибридном элементе управления сетка-дерево. Задача приложения GUI – показать, как:
• Расширить маршалирование очень простой сериализации для ваших собственных классов
• Использовать простой контроль версий
• Очень простая сериализация справляется с реальным кодом – защищенными конструкторами, виртуальными пустыми функциями, и т.д.
• Создание динамических объектов – и как очень простая сериализация обрабатывает ошибки
Когда использовать
У данной методики есть много применений, включая сохранение настроек программы, сохранение состояния для операций отмены/восстановления, автоматической активации форматов файла XML для данных приложения, связи клиент-сервер (т.е. пакеты в проводе) и хранения нереляционных данных в виде XML в базах данных SQL.
Основные особенности
1. Весь код соответствует ISO C++ и переносим
2. Не требует, чтобы постоянные классы имели общий базовый класс
3. Не требует компиляции с поддержкой информации о типе времени исполнения
4. Соблюдает существующий контроль доступа для конструкторов и деструкторов
5. Сериализует указатели на классы/структуры, поддающиеся сериализации
6. Правильно восстанавливает содержимое контейнеров указателей на полиморфные объекты
7. Делает упор на проверку во время компиляции, чтобы минимизировать ошибки при выполнении
8. Макросы используются только для краткости и направляются в отлаживаемый код
9. Реализация полностью встроенная – надо только включить заголовочные файлы очень простой сериализации посредством #include
10. Очень просто добавить новые форматы хранения - JSON, к примеру
Ограничения
1. Требует, чтобы сериализуемые классы имели пустой конструктор
2. Текущая реализация предполагает, что сериализация производится в одном потоке – немного нужно, чтобы добавить безопасность потоков
3. Явно не поддерживает сериализацию типов-указателей 'C', особенно void* и friend(дружественный)
4. Пока не реализовано хранилище строки UNICODE для XML
5. Нет теоретических препятствий к использованию очень простой сериализации с множественным наследованием, но вообще не тестировалось
Соглашения
Во избежание бесчисленных повторений принимается, что любой класс C0 является базовым классом в произвольной иерархии, где C1 унаследован от C0, а C2, в свою очередь, унаследован от C1. Корневой класс описывает «наименее производный» класс. RTTI - информация о типе времени исполнения, и это сокращение применяется при рассмотрении того, как хранить запись имен классов и информацию о наследовании во время выполнения. Следовательно, имеется:
Замечание о макросах и шаблонах
Вкратце, обычно макросы очень полезны при применении с толком. При этом предпочтителен код, поддающийся правильной отладке и предоставляющий возможность легкого тестирования для каждого макроса, а именно - виден ли код или текст во время вхождения в макрос в отладчике?
Макросы ESS_REGISTER, ESS_RTTI и ESS_STREAM используют оператор преобразования в строку (#) для порождения строк из имен классов и экземпляров. Это хорошо, так как уменьшает возможность для ошибки. ESS_RTTI также объявляет дружественный шаблонный класс фабрики, отвечающий за создание новых экземпляров в куче, следовательно, у него есть доступ к защищенным/закрытым конструкторам и деструкторам. Это значительно упрощает применение очень простой сериализации к существующему коду, принося решительную пользу.
Если в макросе содержится исполняемый код, он всегда направляется в шаблонную встроенную функцию для обеспечения правильной отладки. Например:
// тривиальный
#define ESS_ROOT(rootname) typedef ess::root<rootname> ess_root;
// направляется в шаблонную функцию
#define ESS_STREAM(stream_adapter,class_member) \
ess::stream(stream_adapter,class_member,#class_member)
// и чуть более сложная комбинация ...
#define ESS_RTTI(classname,rootname)\
friend ess::CFactory<classname,rootname>; \
virtual const char* get_name()\
{ return ess::get_name_impl<classname>(#classname); }\
static ess::class_registry<classname>* get_registry()\
{ return ess::get_registry_root<classname,rootname>(#rootname); }
ESS_RTTI – самый сложный из макросов очень простой сериализации.
Еще одно философское заявление: шаблоны прекрасны, но метапрограммирование шаблона – нет. Почему? Метапрограммирование шаблона не выдерживает тест отладчика.