关于C++:在抽象基类中有模板函数的方法吗?

Any way to have a template function in an abstract base class?

我正在尝试创建一个配置管理器类,它可以通过std::string存储任意对象。

我对接口(抽象基类)的最初想法是这样的(当然这是非常不完整的)

1
2
3
4
5
6
7
8
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。

最好的方法是什么?


生成一个返回boost::any的受保护虚拟抽象函数,以及一个非虚拟、非抽象、公共模板函数,以对界面的用户隐藏它。

1
2
3
4
5
6
7
8
9
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));
    }
};


另一种方法是将派生类型的名称传递给ConfigurationManager

1
2
3
4
5
6
7
8
9
10
11
12
13
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的定义如下:

1
2
3
4
5
6
7
8
class Foo : public ConfigurationManager<Foo>
{
  template<typename T>
  T getOption(const std::string& name)
  {
    // do something Foo-specific here
  }
};

最终结果类似于抽象的虚拟函数。这个习语被称为奇怪的重复模板模式。


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

1
2
3
4
5
6
7
8
9
class ConfigurationManager
{
   public:
      ...
      template<typename T>
      getOption(...);
   private:
      virtual getOptionSpecial(...) = 0; //Called within getOption
};

对这个问题的最佳答案是(部分)为什么我认为这几乎是你所能做的。