// Базовый тип для всех изображений. class image_t : public oess_1::stdsn::serializable_t { OESS_SERIALIZER( image_t ) public : virtual ~image_t(); ... }; // Тип, который использует изображения. class scheme_item_t : public oess_1::stdsn::serializable_t { OESS_SERIALIZER( scheme_item_t ) private : // Подпись под элементом. std::string m_title; // Изображение для элемента. image_t * m_image; public : ... };
Что на DDL представляется следующим образом:
{type image_t || Тег {super} не указывается, т.к. тип производен от serializable_t. ... } {type scheme_item_t {attr m_title {of std::string}} {attr m_image {of {ptr} image_t}} }
Со временем может быть создано много классов для представления изображений:
// Базовый тип для растровых изображений. class raster_image_t : public image_t { OESS_SERIALIZER( raster_image_t ) ... }; // Изображение в формате GIF. class gif_image_t : public raster_image_t { OESS_SERIALIZER( gif_image_t ) ... }; // Изображение в формате JPEG. class jpeg_image_t : public raster_image_t { OESS_SERIALIZER( jpeg_image_t ) ... }; // Базовый тип для векторных изображений. class vector_image_t : public image_t { OESS_SERIALIZER( vector_image_t ) ... }; // Изображение в формате SVG. class svg_image_t : public vector_image_t { OESS_SERIALIZER( svg_image_t ) ... };
Что на DDL представляется следующим образом:
{type raster_image_t {super image_t} ... } {type gif_image_t {super raster_image_t} ... } {type jpeg_image_t {super raster_image_t} ... } {type vector_image_t {super image_t} ... } {type svg_image_t {super vector_image_t} ... }
При сериализации атрибута scheme_item_t::m_image ObjESSty сохранит в сериализованном представлении реальное имя типа, которому принадлежит объект-изображение. При десериализации ObjESSty сначала извлекает имя типа, ищет специальную фабрику для этого типа и создает объект-изображение. После чего производится десериализация объекта-изображения. Если фабрики для объекта-изображения нет, то десериализация прерывается исключением.
Для того, чтобы иметь возможность при десериализации создавать объекты полиморфных типов, ObjESSty строит для каждого сериализуемого типа специальную фабрику. ObjESSty так же поддерживает список всех фабрик, определенных в приложении. При десериализации атрибута-указателя этот список просматривается в поисках необходимой фабрики. Технически, этот механизм реализуется с помощью типов oess_1::stdsn::factory_registrator_t и oess_1::stdsn::obj_factory_t.
class scheme_item_t : public oess_1::stdsn::serializable_t { OESS_SERIALIZER( scheme_item_t ) private : // Надпись под элементом. std::string m_title; // Параметры шрифта для надписи (шрифт, обычный/курсив/жирный, // подчертнутый/перечеркнутый, цвет, угол наклона, ...). // Если параметры не заданы, то должен использоваться текущий шрифт. // Хранить в этом случае параметры шрифта в объекте не выгодно. // Поэтому, если собственные параметры шрифта для объекта не // заданы, то этот указатель содержит 0. font_params_t * m_font_params; ... };
{type scheme_item_t {attr m_title {of std::string}} {attr m_font_params {of {ptr} font_params_t}} }
При сериализации атрибутов-указателей ObjESSty проверяет, равен ли указатель нулю. Если равен, то в сериализованном представлении сохраняется признак отсутствия значения атрибута. При десериализации этот признак обрабатывается и атрибуту-указателю присваивается нулевое значение.
{type scheme_t {attr m_items || Порядок элементов важен, поэтому используем std::vector. {stl-vector} || Элементами вектора могут быть любые классы, производные от || scheme_item_t. {of {ptr} scheme_item_t} } ... }
ObjESSty преднамерено не поддерживает (пока) работу с циклическими структурами, т.к. наличие циклических ссылок требует двухшаговых операций сериализации и десериализации. Это означает как усложнение алгоритма сериализации/десериализации, так и существенное увеличение времени выполнения данных операций. Кроме того, ситуация усложняется еще и тем, что в ObjESSty существуют механизмы расширяемых типов и неизвестных расширений. Пока не понятно как поступать в случае, если сериализованная на одной стороне циклическая структура не сможет быть полностью десериализованной на другой стороне, т.к. вторая сторона использует более старую схему данных и часть объектов ей просто недоступны, т.к. находятся в неизвестном расширении.
Диагностирование попытки сериализации циклической структуры пока так же затруднена тем, что из-за поддержки множественного и виртуального множественного наследования вполне легальными являются ситуации, когда некоторая базовая составляющая сохраняемого типа задействуется при сериализации/десериализации несколько раз. Например:
{type A ... } {type B {super {virtual} A } ...} {type C {super {virtual} C } ...} {type D {super B} {super C} ...}
Лучше всего всегда хранить в атрибутах-указателях указатели на динамически созданные объекты. Тогда в деструкторе сериализуемого типа можно смело вызывать для них delete.
Если такие случаи возможны, то следует воспользоваться механизмом subclassing by extension: oess_1.2.0. Наследование расширением (subclassing_by_extension).