C ++:奇怪的重复模板模式是什么?并且可以奇怪地重复模板模式取代虚拟功能?

时间:2013-06-07 16:05:47

标签: c++ templates virtual-functions crtp

我没有对问题的准确描述,所以我只是问这是否可能(如果是的话,其他一些信息会很棒)。

程序员告诉我,你可以避免虚函数/多态导致的运行时开销。他说为了避免运行时开销,你可以在名为Curiously_recurring_template_pattern的模式中使用模板,它看起来像这样:

class Derived : public Base<Derived>
{
  // ... implementation here
};

这个奇怪的重复模板模式如何运作?

如何使用Curiously-Recurring-Template-Pattern替换正常的虚函数/多态?

我弄错了吗?

4 个答案:

答案 0 :(得分:19)

非常具体地说,可以使用CRTP代替具有虚函数的基类来实现template method pattern而无需虚函数调用开销。

使用虚函数,TMP如下所示:

class ProvidesMethod {
protected:
  void Method() {
    // do something
    Part1();
    // do something else
    Part2();
    // do something final
  }

private:
  virtual void Part1() = 0;
  virtual void Part2() = 0;
};

class ExposesMethod : private ProvidesMethod {
public:
  using ProvidesMethod::Method;

private:
  void Part1() {
    // first part implementation
  }
  void Part2() {
    // second part implementation
  }
};

使用CRTP,它看起来像这样:

template <typename Derived>
class ProvidesMethod {
protected:
  void Method() {
    // do something
    self().Part1();
    // do something else
    self().Part2();
    // do something final
  }

private:
  Derived& self() { return *static_cast<Derived*>(this); }
  const Derived& self() const { return *static_cast<const Derived*>(this); }
};

class ExposesMethod : private ProvidesMethod<ExposesMethod> {
public:
  using ProvidesMethod<ExposesMethod>::Method;

private:
  friend class ProvidesMethod<ExposesMethod>;
  void Part1() {
    // first part implementation
  }
  void Part2() {
    // second part implementation
  }
};

答案 1 :(得分:3)

这称为CRTP(用于奇怪的重复模板模式),因此您可以查找它。

虽然我真的没有看到它如何取代经典的多态性......

另一方面,在某些情况下,可以通过模板替换类的复杂层次结构(有关更多信息,请参阅基于策略的设计),但并不总是可行...

答案 2 :(得分:3)

正如Julien所说,这是CRTP。你应该查一查。 但CRTP无法取代虚拟功能。如果它在特定情况下适用于您,那么您实际上并不需要虚拟功能。 看,模板提供了编译时多态性。虚函数提供运行时多态性。如果您不知道在编译时将调用哪个覆盖,那么基于模板的解决方案将不起作用。如果您始终知道对象的实际类型在运行时将是什么,那么您不需要虚函数。

答案 3 :(得分:2)

我不确定你会如何使用模板来提供像虚函数这样的东西 - 这对我来说似乎很奇怪 - 当然没有一堆诡计最终相当于实现你自己版本的虚函数而不是使用编译器提供的虚函数,我发现很难看出你如何能够调用函数的代码不知道对象是什么类型,并为该对象类型调用正确的函数。这是虚函数的功能。

此外,从个人经验来看,虚拟功能的ACTUAL开销非常小,只有在非常极端的情况下它会产生影响(非虚拟功能内联的主要情况,并且开销非常小)调用函数是总执行时间的重要部分(这也意味着函数需要多次调用才能产生任何显着差异)。如果你必须“弄清楚要做什么”,会有更多的开销(使用if语句或类似的东西)以某种其他方式[除了在“虚拟功能”上实现你自己的变化,但这只是重新发明轮子,除非你的新轮子比现有的更好,这不是一个好主意]。