← 模式
将行为委托给派生类
1234567891011121314151617181920212223242526272829303132333435 | template<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 行的 foo
和 bar
类,通过继承 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 行)。