Возможно ли создать экземпляр объекта с учетом его типа в C ++? - PullRequest
2 голосов
/ 22 ноября 2010

Я слишком долго программировал на Java и нашел свой путь назад к некоторому C ++.Я хочу написать некоторый код, который дает классу (либо type_info, либо его имя в строке), может создать экземпляр этого класса.Для простоты давайте предположим, что для этого нужно только вызвать конструктор по умолчанию.Возможно ли это даже в C ++, и если нет, то будет ли это в будущем TR?

Я нашел способ сделать это, но я надеюсь, что есть что-то более «динамичное».Для классов, которые я хотел бы создать (это само по себе является проблемой, поскольку я хочу оставить это решение до конфигурации), я создал одноэлементную фабрику со статически созданным экземпляром, который регистрирует себя в другом классе.например.для класса Foo также существует FooFactory, который имеет статический экземпляр FooFactory, так что при запуске программы вызывается конструктор FooFactory, который регистрируется в другом классе.Затем, когда я хочу создать Foo во время выполнения, я нахожу FooFactory и вызываю его для создания экземпляра Foo.Есть ли что-нибудь лучше для этого в C ++?Я предполагаю, что меня только что избаловало богатое отражение в Java / C #.

Для контекста я пытаюсь применить некоторые концепции контейнеров IOC, к которым я так привык в мире Javaв C ++, и надеясь, что смогу сделать его максимально динамичным, без необходимости добавлять класс Factory для каждого другого класса в моем приложении.

Ответы [ 4 ]

0 голосов
/ 22 ноября 2010

Добро пожаловать в 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.

0 голосов
/ 22 ноября 2010

Нет.Нет способа добраться от имени типа к фактическому типу;богатое отражение довольно круто, но почти всегда есть лучший способ.

0 голосов
/ 22 ноября 2010

нет такой вещи, как "var" или "dynamic" в C ++ в прошлый раз, когда я проверял (хотя это было некоторое время назад).Вы можете использовать указатель (void *) и затем попытаться выполнить приведение соответственно.Кроме того, если память мне не изменяет, в C ++ есть RTTI, который не является отражением, но может помочь в определении типов во время выполнения.

0 голосов
/ 22 ноября 2010

Вы всегда можете использовать шаблоны, хотя я не уверен, что это то, что вы ищете:

template <typename T>
T
instantiate ()
{
  return T ();
}

Или в классе:

template <typename T>
class MyClass
{
  ...
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...