Есть ли способ иметь шаблонную функцию в абстрактном базовом классе? - PullRequest
9 голосов
/ 23 декабря 2011

Я пытаюсь создать класс менеджера конфигурации, который может хранить произвольные объекты с помощью std :: string.

Моя исходная идея для моего интерфейса (абстрактный базовый класс) заключалась в следующем (конечно, это ужасно неполно)

class ConfigurationManager
{
public:
   static boost::shared_ptr<ConfigurationManager> create();

   template<typename T>
   virtual T getOption(const std::string& name) = 0;
};

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

Внутренне я собираюсь использовать boost:: any (в значительной степени проверено время выполнения void *), но я не хочу показывать boost :: any в моем интерфейсе.

Как лучше всего это сделать?

Ответы [ 3 ]

7 голосов
/ 23 декабря 2011

Создайте защищенную виртуальную абстрактную функцию, возвращающую boost::any, и не виртуальную, неабстрактную, публичную функцию шаблона, чтобы скрыть ее от пользователей вашего интерфейса.

class ConfigurationManager {
protected:
    virtual boost::any getOptionProtected(const std::string& name) = 0;
public:
    static boost::shared_ptr<ConfigurationManager> create();
    template<typename T> T getOption(const std::string& name) {
        return boost::any_cast<T>(getOptionProtected(name));
    }
};
4 голосов
/ 23 декабря 2011

Альтернативный подход - передать имя производного типа в ConfigurationManager:

template<typename Derived>
class ConfigurationManager
{
  public:
    static boost::shared_ptr<ConfigurationManager> create();

  template<typename T>
  T getOption(const std::string& name)
  {
    // call Derived::getOption
    return static_cast<Derived*>(this)->getOption(name);
  }
};

Производный тип Foo будет определен так:1008 * Конечным результатом является нечто похожее на абстрактную виртуальную функцию.Эта идиома упоминается как любопытно повторяющийся шаблон .

1 голос
/ 23 декабря 2011

Я не знаю, что boost::any делает для вас, но кроме этого ваши (только, я думаю) варианты: 1) Сделать ConfigurationManager классом шаблона или 2) сделать ConfigurationManager::getOption не -virtual, но использует отдельную не шаблонную виртуальную функцию (которая вызывается в getOption), которая управляет функциональностью, которую вы хотите в своих производных классах. Есть также варианты на 2), такие как включение указателя на объект, который определяет предполагаемую функциональность (не виртуальную) getOption. Этот объект будет экземпляром класса, который сам является частью иерархии наследования - в основном, паттерна Стратегия. Кажется, сложнее, хотя. Так что в основном я предлагаю

class ConfigurationManager
{
   public:
      ...
      template<typename T>
      getOption(...);
   private:
      virtual getOptionSpecial(...) = 0; //Called within getOption
};

Главный ответ на этот SO поток (частично), почему я думаю, что это почти все, что вы можете сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...