【问题标题】:Any way to have a template function in an abstract base class?有什么方法可以在抽象基类中使用模板函数?
【发布时间】:2012-01-26 12:48:50
【问题描述】:

我正在尝试制作一个配置管理器类,它可以通过 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。

最好的方法是什么?

【问题讨论】:

  • @Oli 模拟我在问题中发布的语法上不可能的界面。
  • 所以你想做多态函数模板,即使它们是不可能的?

标签: c++ virtual abstract-class


【解决方案1】:

创建一个返回 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));
    }
};

【讨论】:

  • 最终几乎完全使用了这个。
【解决方案2】:

另一种方法是将派生类型的名称传递给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 将被定义如下:

class Foo : public ConfigurationManager<Foo>
{
  template<typename T>
  T getOption(const std::string& name)
  {
    // do something Foo-specific here
  }
};

最终结果类似于抽象虚函数。这个成语被称为curiously recurring template pattern

【讨论】:

  • 我知道这已经过时了,但是在这种 CRTP 的使用中,ConfigurationManager 类的意义何在?我们不能使用该类型来存储 Foo。
【解决方案3】:

我不知道 boost::any 为您做了什么,但除此之外,您的(我认为唯一的)选项是 1)将 ConfigurationManager 设为模板类,或 2)将 ConfigurationManager::getOption 设为 non-virtual 但使用单独的非模板虚函数(在getOption 中调用)来管理您在派生类中需要的功能。 2) 也有变体,例如包含一个指向对象的指针,该对象指定(非虚拟)getOption 的预期功能。这个对象将是一个类的实例,它本身就是继承层次结构的一部分——基本上是策略模式。不过似乎更复杂。所以基本上我是建议

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

this SO thread 的最佳答案是(部分)为什么我认为这几乎是你所能做的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-07
    • 1970-01-01
    • 2011-09-10
    • 1970-01-01
    • 2013-10-08
    相关资源
    最近更新 更多