2010-11-21 2 views
2

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

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

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

+0

В качестве продолжения можно передать «тип» в C++? то есть. передать не объект Foo, а класс Foo, как параметр функции? Явный эквивалент Java, который я рассматриваю, - это метод, который принимает параметр класса, и вы можете перейти в Foo.class – Greencpp

ответ

0

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

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

Или по классу:

template <typename T> 
class MyClass 
{ 
    ... 
}; 
+0

Спасибо Джо. Да, использование шаблонов может быть способом обрезать строки кода, необходимые для реализации фабрики, однако я надеюсь найти способ избежать создания фабрики в каждом классе для динамического создания. Я подозреваю, что не буду. – Greencpp

-1

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

+1

Да, я подозреваю, что попытка оптовой подгонки Java-способа сделать IOC на C++ - моя первая ошибка. Тем не менее, возможность динамического подключения классов в конфигурации a la Spring очень эффективна. Мой заводский подход удовлетворяет это желание, но не так чисто, как хотелось бы. – Greencpp

+1

BTW, который дал здесь -1, и почему ... Мне интересно, почему вы не согласны с Джонатаном. – Greencpp

+0

lol :) Каждый свой. –

-1

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

+1

C++ 0x 'auto' - это в значительной степени то, что C#' var'. И оба они не имеют ничего общего с динамической типизацией. – fredoverflow

0

Добро пожаловать в C++ :)

Вы правы, что вам нужно Factory создавать эти объекты, однако вам может не понадобиться один Factory на файл.

Типичный способ идти на это иметь все instanciable классов происходят от общего базового класса, который мы будем называть 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 (или его эквиваленте) после того, как вы имеют необходимые параметры.

Краткое примечание: указатель на метод функций является наиболее экономичным (в памяти) и быстрый (в исполнении), но синтаксис странно ...

Что касается последующих вопросов.

Да можно передать тип к функции, хотя, возможно, не сразу:

  • если тип в вопросе известно во время компиляции, вы можете использовать шаблоны, если вы будете нуждаться в некоторых время, чтобы ознакомиться с синтаксисом
  • , если нет, то вам необходимо пройти какой-то ID и использовать на заводе подход

Если вам нужно передать что-то похожее на object.class то мне кажется, что вы приближаетесь к варианту использования двойной отправки и стоит посмотреть на шаблон Visitor.

Смежные вопросы