Возможно ли в C ++ зациклить все подклассы абстрактного класса? - PullRequest
4 голосов
/ 27 марта 2011

У меня есть абстрактный класс в C ++ с несколькими подклассами.

Возможно ли как-то с помощью макросов или шаблонного метапрограммирования сделать что-то подобное:

foreach subclass of Base:
  mymap[subclass::SOME_CONSTANT] = new subclass();

Ответы [ 2 ]

7 голосов
/ 27 марта 2011

Нет, вы не можете.

То, что вы хотите, по-видимому, это Factory (или, возможно, Abstract Factory).

В C ++ вы устанавливаете класс Factory и регистрируете компоновщики.

class FooFactory
{
public:
  typedef std::function<Foo*()> Builder;

  /// returns true if the registration succeeded, false otherwise
  bool Register(std::string const& key, Builder const& builder) {
    return map.insert(std::make_pair(key, builder)).second;
  }

  /// returns a pointer to a new instance of Foo (or a derived class)
  /// if the key was found, 0 otherwise
  Foo* Build(std::string const& key) const {
    auto it = _map.find(key);
    if (it == _map.end()) { return 0; } // no such key
    return (it->second)();
  }

private:
  std::map<std::string, Builder> _map;
};

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

FooFactory& GetFooFactory() { static FooFactory F; return F; }

И вы можете подготовить удобного строителя:

template <typename Derived>
Foo* fooBuilder() { return new Derived(); }

Затем ожидается, что люди зарегистрируют свои производные классы на фабрике:

static const bool registeredBar =
    GetFooFactory().Register("Bar", fooBuilder<Bar>);

Примечание. Фабрика должна быть далеко не обязательной, поскольку фабрика должна быть одноэлементной, хотя здесь это не так плохо, потому что она постоянна после окончания загрузки библиотек.

Примечание: для правильной архитектуры плагинов вам нужно будет использовать RAII (вместо bool) для обработки отмены регистрации при выгрузке библиотеки. Это гораздо реже.

0 голосов
/ 27 марта 2011

C ++ не позволяет перебирать типы. Также перечисление членов enum невозможно. Смотрите это:

enum Color
{
    red,
    green,
    blue=5,
    yellow
};

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

...