← 模式

将行为委托给派生类

1234567891011121314151617181920212223242526272829303132333435template<typename derived> class base { public: void do_something() { // ... static_cast<derived*>(this)->do_something_impl(); // ... } private: void do_something_impl() { // 默认实现 } }; class foo : public base<foo> { public: void do_something_impl() { // 派生类实现 } }; class bar : public base<bar> { }; template<typename derived> void use(base<derived>& b) { b.do_something(); }

此模式采用 CC0 公共领域贡献 许可。

要求 c++98 或更新版本。

意图

将行为委托给派生类,而不产生运行时多态的开销。

描述

通过奇异递归模板模式(Curiously Recurring Template Pattern, CRTP),它提供了一种静态多态的形式,我们可以将行为从基类委托给其派生类。这种方法避免了使用 virtual 函数实现运行时多态所带来的开销,后者通常通过虚函数表(一种动态派发机制)来实现。

第 19-29 行foobar 类,通过继承 base 类模板(第 1-17 行)并提供自身作为模板参数,演示了 CRTP 惯用法。例如,在第 19 行foo 继承自 base<foo>。这使得 base 能够在编译时知道是哪个类继承了它。

base 类提供了一个公共成员函数 do_something第 5-10 行),它依赖于一个内部函数 do_something_impl,派生类可以选择性地重写该函数。通过这种方式,base 能够将行为委托给派生类。在第 13-16 行给出了该函数的默认实现,而 foo 类在第 22-25 行提供了自己的实现。为确保使用正确的实现,do_something 函数在第 8 行this 强制转换为指向派生类型的指针,并调用其 do_something_impl 方法。

第 31-35 行use 函数模板接受一个对 base 任意实例化的引用,并调用其 do_something 方法。由于派生类型在编译时已知,因此无需动态派发即可调用正确的实现函数。例如,如果提供的是 base<foo>,那么 foo 的实现(第 22-25 行)将被调用。另一方面,对于 base<bar>,则会使用 base 定义的默认实现(第 13-16 行)。

贡献者

  • Joseph Mansfield
  • Michael B. Price
  • Migrant Coder

最后更新

2017年12月9日

来源

在 GitHub 上 Fork 此模式

分享