C ++模板与继承

时间:2011-07-06 08:40:11

标签: c++ templates inheritance code-complexity

我只是意识到提出问题有多难...希望我能举出两个例子,足够精确地展示我的问题,并且足够短,不要弄乱一切......至少可以编辑。< / p>

所以这就是我目前的情况。当然,我在逻辑/结构(以及无论如何命名方面)方面对它进行了一些修改,试图关注我问题的本质:

// MyClass deals with lists (actually several data structures) of the
// type MyType which should support different types and has to be 
// efficiently dealt with. Templating seems just right here
class MyClass
{
  ...

  void doSomething<class MyType>(vector<MyType> someList);

  ...

  // At some point I have to extract elements of the type MyType.
  // The extractor obviously depends on MyType but it is not possible to
  // Create a general version that could use templates itself 
  // (unless I use a specialization for each possible MyType)

  // I am stuck between these two alternatives:

  // Possibility1:
  // Let the client pass the right extractor and template it.
  template<class Extractor, class MyType>
  void extract(const Extractor& extractor, const string& source, 
               vector<MyType>* dest)
  {
     extractor.extract(source, dest);
  }

  // Possibility2:
  // Use a member _extractor of some base type that has to be set
  // to a specialization. The ExtractorBase has a virtual method
  // template<T> void extract(const string& source, vector<T>* myType) = 0
  // with no definition that is only defined in subclasses wrt certain
  // postings.
  ExtractorBase _extractor;

  template<class MyType>
  void extract(const string& source, vector<MyType>* dest)
  {
     _extractor.extract(source, dest);
  }
}

目前我更喜欢possible1,因为我不需要在Extractor中使用MyType的所有变体以及我希望将来尝试的相关Extractor的继承。

另一方面,提取器可能需要复杂的代码和几个成员(类似于映射某些值的某些输入的巨大地图)。因此,使用模板不会带来性能提升。特别是使用头文件只有Extractors,甚至可能是内联的仿函数,都是不可能的。在过去,这一直是我的一个强有力的指针,模板化只会增加代码复杂性(必须处理实例化,使客户端代码生活更加困难等),我应该尽量避免使用它。

或者有没有第三种可能性我完全没有想到?

4 个答案:

答案 0 :(得分:2)

最好使用第一个选项。它更清洁,更易于维护。

因为根据你的评论,我发现你正在为第二个选项做出错误的假设:

// The ExtractorBase has a virtual method
// template<T> void extract(const string& source, vector<T>* myType) = 0;

即可。那是不可能的; template函数永远不会是virtual。所以要实现第二个选项,你必须选择一些肮脏且难以维护的方法,这不是一个好主意。

答案 1 :(得分:1)

我认为第一种可能性更灵活。

在第二种可能性中,我没有看到不需要的封装提取器作为类成员的兴趣。你在MyClass和Extractor之间也有更多的耦合,这不是一件好事。模板减少了耦合(以某种方式),所以如果你有选择它是一个更好的。

答案 2 :(得分:1)

你有第三个选项,为MyType提供一个构造函数,它知道如何从std::string构造自己。或者更好的是一对迭代器,所以如果你需要从字符串构造一个MyType s序列,你可以使用该范围。

答案 3 :(得分:0)

这听起来像Strategy Pattern的情况 - 你的班级有一个实施可能会有所不同的操作。

这是我在不同方法中看到的权衡。

模板解决方案将避免必须声明抽象接口类,并使用vtbl来确定要使用的实现。但是它会强制你在编译时锁定应用程序。

继承解决方案将强制您声明一个抽象接口类,并在vtbl.中查看实现的性能命中但它允许您在运行时选择提取实现。

我不知道你的应用程序的性能有多关键以及你需要多么灵活,我可能会选择继承解决方案,因为我喜欢在抽象类中定义接口并对其进行编码的清晰度。