На самом деле это более общая проблема, чем сериализация, называемая Virtual Constructor
.
. Традиционный подход к Factory
, который на основе идентификатора возвращает правильный производный тип.Существует два решения:
- метод
switch
, как вы заметили, хотя вам нужно выделить в куче - метод
prototype
Метод-прототип выглядит следующим образом:
// Cloneability
class Base
{
public:
virtual Base* clone() const = 0;
};
class Derived: public Base
{
public:
virtual Derived* clone() const { return new Derived(*this); }
};
// Factory
class Factory
{
public:
Base* get(std::string const& id) const;
void set(std::string const& id, Base* exemplar);
private:
typedef std::map < std::string, Base* > exemplars_type;
exemplars_type mExemplars;
};
Несколько традиционно Factory
делают синглтоном, но это совсем другое дело.
Для правильной десериализации проще, если выиметь виртуальный метод deserialize
для вызова объекта.
РЕДАКТИРОВАТЬ: Как работает Фабрика?
В C ++ вы не можете создать тип, о котором вы не знаете.Поэтому идея выше заключается в том, что задача создания объекта Derived
передается классу Derived
с помощью метода clone
.
Далее следует Factory
.Мы собираемся использовать map
, который будет ассоциировать «тег» (например, "Derived"
) с экземпляром объекта (скажем, Derived
здесь).
Factory factory;
Derived derived;
factory.set("Derived", &derived);
Теперь, когда мыЕсли мы хотим создать объект, тип которого мы не знаем во время компиляции (поскольку тип определяется на лету), мы передаем тег фабрике и запрашиваем взамен объект.
std::unique_ptr<Base> base = factory.get("Derived");
Под крышкой Factory
найдет Base*
, связанный с тегом "Derived"
, и вызовет метод clone
объекта.Это фактически (здесь) создаст объект типа времени выполнения Derived
.
. Мы можем проверить это с помощью оператора typeid
:
assert( typeid(base) == typeid(Derived) );