Добро пожаловать в C ++:)
Вы правы, что вам понадобится Factory
для создания этих объектов, однако вам может не понадобиться один Factory
на файл.
Типичный способ сделать это - все классы, которые могут быть созданы, являются производными от общего базового класса, который мы назовем Base
, так что вам понадобится один Factory
, который будет служить вам std::unique_ptr<Base>
каждый раз.
Существует 2 способа реализации Factory
:
- Вы можете использовать шаблон
Prototype
и зарегистрировать экземпляр класса для создания, для которого будет вызываться функция clone
.
- Вы можете зарегистрировать указатель на функцию или функтор (или
std::function<Base*()>
в C ++ 0x)
Конечно, сложность состоит в том, чтобы зарегистрировать эти записи динамически. Обычно это делается при запуске во время статической инициализации.
// OO-way
class Derived: public Base
{
public:
virtual Derived* clone() const { return new Derived(*this); }
private:
};
// start-up...
namespace { Base* derived = GetFactory().register("Derived", new Derived); }
// ...or in main
int main(int argc, char* argv[])
{
GetFactory().register("Derived", new Derived(argv[1]));
}
// Pointer to function
class Derived: public Base {};
// C++03
namespace {
Base* makeDerived() { return new Derived; }
Base* derived = GetFactory().register("Derived", makeDerived);
}
// C++0x
namespace {
Base* derived = GetFactory().register("Derived", []() { return new Derived; });
}
Основным преимуществом способа запуска является то, что вы можете точно определить свой класс Derived
в своем собственном файле, сохранить регистрацию там, и ваши изменения не повлияют на другой файл. Это отлично подходит для обработки зависимостей.
С другой стороны, если прототип, который вы хотите создать, требует некоторой внешней информации / параметров, тогда вы вынуждены использовать метод инициализации, самый простой из которых - зарегистрировать свой экземпляр в main
(или эквивалентном) один раз. у вас есть необходимые параметры.
Краткое примечание: указатель на метод функции является наиболее экономичным (в памяти) и самым быстрым (при исполнении), но синтаксис странный ...
Относительно последующих вопросов.
Да, можно передать тип функции, хотя, возможно, не напрямую:
- если рассматриваемый тип известен во время компиляции, вы можете использовать шаблоны, хотя вам потребуется некоторое время, чтобы ознакомиться с синтаксисом
- если нет, то вам нужно будет передать какой-то идентификатор и использовать заводской подход
Если вам нужно передать что-то похожее на object.class
, тогда мне кажется, что вы подходите к варианту использования с двойной отправкой, и стоило бы взглянуть на шаблон Visitor
.