Сделать объект по имени - PullRequest
2 голосов
/ 16 января 2011

возможно ли вернуть образец объекта, используя переданное имя типа (строку) в c ++?У меня есть базовый абстрактный класс Base и несколько производных.Пример кода:

class Base
{
   /* ... */
};

class Der1 : public Base
{
   /* ... */
};

class Der2 : public Base
{
   /* ... */
};

И мне нужна такая функция:

Base *objectByType(const std::string &name);

Количество производных классов можно изменить, и я не хочу делать что-то вроде переключения name и возвратаруками новый тип объекта.Возможно ли в c ++ сделать это автоматически в любом случае?

ps использование должно выглядеть так:

dynamic_cast<Der1>(objectByType("Der1"));

Мне нужен чистый код на C ++ (кроссплатформенный)Использование наддува допустимо.

Ответы [ 6 ]

2 голосов
/ 16 января 2011

Есть хороший трюк, который позволяет написать фабричный метод без последовательности if...else if....

(обратите внимание, что, AFAIK, в C ++ действительно невозможно делать то, что вы хотите, так как этот код генерируется во время компиляции. Для этого существует "фабричный метод" Шаблон проектирования ) 1008 *

Сначала вы определяете global repository для ваших производных классов. Он может иметь вид std::map<std::string, Base*>, то есть отображает имя производного класса в an instance этого класса.

Для каждого производного класса вы определяете default constructor, который добавляет объект этого класса в хранилище под именем класса. Вы также определяете статический экземпляр класса:

// file: der1.h
#include "repository.h"

class Der1: public Base {
public:
  Der1() { repository[std::string("Der1")] = this; }
};

// file: der1.cpp
static Der1 der1Initializer;

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

Ваш фабричный метод (например, Base::getObject(const std::string&)) должен найти в карте хранилища имя класса. Затем он использует метод clone() объекта, который он находит, чтобы получить новый объект того же типа. Вам, конечно, нужно реализовать clone для каждого подкласса.

Преимущество этого подхода в том, что при добавлении нового производного класса ваши добавления ограничиваются только файлами, реализующими новый класс. Хранилище и заводской код не изменятся. Конечно, вам все равно придется перекомпилировать программу.

2 голосов
/ 16 января 2011

Это не возможно сделать в C ++.

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

0 голосов
/ 16 января 2011

C ++ не поддерживает отражение .

На мой взгляд, это единственная точка, в которой Java побеждает C ++.
(чтобы не набрать слишком много голосов за это ...)

Вы можете достичь чего-то подобного, используя собственный препроцессор, аналогично тому, как MOC делает для Qt.

0 голосов
/ 16 января 2011

Это невозможно. Вы должны написать функцию objectByType самостоятельно:

Base* objectByType(const std::string& name) {
  if (name == "Der1")
    return new Der1;
  else if (name == "Der2")
    return new Der2;
  // other possible tests
  throw std::invalid_argument("Unknown type name " + name);
}
0 голосов
/ 16 января 2011

Если я неправильно понял, ключевое слово typeid должно быть частью того, что вы ищете.

0 голосов
/ 16 января 2011

Да, это возможно!Проверьте этот очень забавный класс с именем Activator. Вы можете создать все с помощью Type и string и даже можете дать список параметров, поэтому метод вызовет соответствующий конструктор с наилучшим набором аргументов..

...