The serialization library needs a system like
type_info/typeid() to perform
the following functions
given a pointer to a type T discover the true type pointed to.
given an "external" key - determine what type of object to create.
The problem with std::type_info
The main function we require - std::typeid()
is not available in all environments. Support for this function depends upon
runtime typing(RTTI) support from the compiler. This may be non-existent
or not enabled for reasons such as a percieved inefficiency.
std::type_info includes a string
containing type name. This would seem to satisfy 2) above.
But the format of this string is not consistent accross compilers, libraries,
and operating systems. This makes it unusable for support of portable archives.
Even if the type name string could somehow be made portable, there is no
guarantee that class headers would be included in the same namespace accross
different applications. In fact, including different headers in different
namespaces is an accepted method used to avoid namespace conflicts.
Thus the namespace::class_name can't be used as a key.
There exists the possibility that different classes use different type id
mechanisms. The class header might include this information. If we want to
import class headers accross applications, it's convenient that the type id
mechanism support inter-operability accross different type id systems.
Features
extended_type_info is an implementation
of std::type_info functionality with the
following features:
Builds a set of extended_type_info records - one for each type
serialized.
permits association of an arbitrary string key with a type. Often this key would
be the class name - but it doesn't have to be. This key is referred to as
a GUID - Globally Unique IDentifier. Presumably it should be unique in the universe.
Typically this GUID would be in header files and be used to match type accross
applications. The macro BOOST_CLASS_EXPORT can be invoked to associate a string
key with any known type. We'll refer to these types as "exported types"
permits the "mixing" of type info systems. For example, one class might use
typeid() to find the external identifier
of a class while another might not.
Exported types are maintained in a global table so that given a string key, the
corresponding type can be found. This facility is used by the serialization library
in order to construct types serialized through a base class pointer.
namespace boost {
namespace serialization {
class extended_type_info
{
protected:
// this class can't be used as is. It's just the
// common functionality for all type_info replacement
// systems. Hence, make these protected
extended_type_info(
const unsigned int type_info_key,
const char * key
);
~extended_type_info();
void key_register();
void key_unregister();
public:
const char * get_key() const;
bool operator<(const extended_type_info &rhs) const;
bool operator==(const extended_type_info &rhs) const;
bool operator!=(const extended_type_info &rhs) const {
return !(operator==(rhs));
}
// for plugins
virtual void * construct(unsigned int count = 0, ...) const;
virtual void destroy(void const * const p) const;
static const extended_type_info * find(const char *key);
};
} // namespace serialization
} // namespace boost
Как правило, для каждого типа создается один и только один экземпляр<extended_type_info>. Однако это осуществляется только на уровне исполняемого модуля. То есть, если программа включает в себя некоторые общие библиотеки или DLLS, может быть более одного экземпляра этого класса, соответствующего определенному типу. По этой причине функции сравнения ниже не могут просто сравнивать адреса этого экземпляра, а должны быть запрограммированы для сравнения фактической информации, содержащейся в экземплярах.
<
extended_type_info(unsigned int type_info_key, const char *key);
>
Этот конструктор должен называться всеми производными классами. Первым аргументом должно быть конкретное осуществление. Для этой базы реализации по умолчанию на typeid(), это значение 1. Каждая система должна иметь свое целое число. Это значение используется для обеспечения совместимости различных систем информации типа.
Второй аргумент — это строка const, которая является внешним названием типа, которому соответствует эта запись. Иногда его можно назвать GUID —GlobalUniqueIDentifier. Он передается через архивы от одного вызова программы к другому, чтобы однозначно определить типы, которые содержит архив. Если «экспортный» объект не будет использоваться, эта стоимость может быть нулевой.
<
void key_register();
void key_unregister();
>
Эта система поддерживает глобальную таблицу, которая связывает внешние строки с<extended_type_info>записями. Эта таблица используется при загрузке указателей на объекты, сериализованные через указатель базового класса. В этом случае архив содержит строку, которая просматривается в этой таблице, чтобы определить, какую<extended_type_info>использовать для создания нового объекта.
Эти функции называются конструкторами и деструкторами классов, которые реализуют<extended_type_info>добавление и удаление записей из этой таблицы.
<
const char *get_key() const;
>
Получает ключ для<extended_type_info>экземпляра. Если ключ не был связан с экземпляром, то NULL возвращается.
Эти функции используются для сравнения.<
extended_type_info
>объекты. Они накладывают строгий общий порядок на все записи<extended_type_info>.
<
virtual void * construct(unsigned int count = 0, ...) const;
>
Постройте новый экземпляр того типа, к которому это<
extended_type_info
>Запись соответствует. Эта функция принимает переменный список до 4 аргументов любого типа. Эти аргументы передаются конструктору типа во время выполнения. Чтобы использовать объект, необходимо объявить последовательность типов для аргументов конструктора. Аргументы для этой функции должны соответствовать по количеству и типу тем, которые указаны при экспорте типа. Эта функция позволяет создавать экземпляры любого экспортируемого типа, учитывая только экспортируемыйГИД, присвоенный BOOST_CLASS_EXPORT. Если эти типы определены в DLLS или общих библиотеках, загружаемых во время выполнения, эти конструкторы могут быть вызваны до тех пор, пока модуль не будет разгружен. Такие модули называютсяплагинами.
<
virtual void destroy(void const * const p) const;
>
Уничтожьте экземпляр, созданный вышеуказанным конструктором.
Для использования библиотекой сериализации реализация<extended_type_info>(здесь ETI) должна быть получена из.<
extended_type_info
>, а также осуществлять
<
template<class ETI>
const extended_type_info *
ETI::get_derived_extended_type_info(const T & t) const;
>
Возврат указателя в экземпляр<extended_type_info>, который соответствует «истинному типу» типа Т. «Истинный тип» — самый низкий тип в иерархии классов. Тип Т всегда можно отлить в «истинный тип» со статическим отливом. Внедрение этой функции будет варьироваться в зависимости от типа системы идентификатора и иногда будет делать предположения о типе T, которые могут быть идентифицированы с конкретной реализацией<extended_type_info>.
Сравните этот пример с другим, используя ту же реализацию<extended_type_info>. Возвращение<true>, если указанные типы одинаковы. В противном случае возвращайте<false>
<
const char ETI::get_key() const;
>
Введите внешний ключ (он же GUID) для этого класса.
<
virtual void * construct(unsigned int count, ...) const;
>
Постройте экземпляр соответствующего типа со списком аргументов.
>реализуется таким образом, чтобы не полагаться на существование RTTI. Вместо этого он требует эксплицитного экспорта всех полиморфных типов. Кроме того, если объект экспорта должен использоваться для сериализации типов через указатели базового класса, эти типы необходимы для реализации виртуальной функции с подписью:<
virtual const char * get_key();
>, которая возвращает уникальную строку наиболее производного объекта этого класса. Эта функция должна быть виртуальной, чтобы реализовать функциональность, требуемую<ETI::get_derived_extended_type_info>, как описано выше.
Тестовая программа<test_no_rtti>реализует эту функцию с точки зрения<
extended_type_info>API выше для возврата экспортного ключа, связанного с классом. Для этого необходимо экспортировать неабстрактные виды. Он также демонстрирует взаимодействие между двумя различными реализациями<extended_type_info>
Каждый тип, управляемый системой, должен быть «зарегистрирован» индивидуально. Это достигается путем создания шаблонов. Например, если тип T использует систему type_info, он будет содержать следующий код:<
>Для тех, кто использует библиотеку сериализации, этот шаг можно пропустить, поскольку он выполняется автоматически. Библиотека сериализации включает макрос:<
>, который используется для указания того, какая<extended_type_info>система должна использоваться для данного типа.
<extended_type_info>включает в себя объект для построения экземпляров типов, не зная, какие именно типы. Это делается с помощью функции<
virtual void * extended_type_info::construct(unsigned int count = 0, ...) const;
>. Например: <
struct base {
...
};
struct derived : public base {
...
};
...
extended_type_info *eti = extended_type_info::find("my_class")
base * b = eti->construct(...);
> <construct>берет количество аргументов и до четырех параметров любого типа. Аргументы передаются конструктору «мой_класса». Полный пример этого можно найти здесь
Статья Serialization - extended_type_info раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.