CRTP

概念

Curiously Recurring Template Pattern,奇异模板递归模式,即基类为类模板,把派生类作为基类的模板参数,基类中的成员函数可以(通过 static_cast 转换为派生类类型)访问派生类的成员函数。

原理

这称作编译期(静态)多态,其原理是利用了基类(类模板)的实例化(为一个独立的类)发生于派生类声明之后,即在派生类声明后才可能调用基类(类模板)中的方法进而进行实例化

功能及使用示例

普通静态多态调用

即通过基类(类模板)实例的引用或指针调用基类中某方法后,又间接调用了派生类中的实现,模似出多态的效果,代码示例

链式静态多态调用

即调用某方法后返回当前实例的引用,支持形如 inst.Func1().Func2().Func3() 的调用。在有发生继承情况时,基类方法需要返回派生类实例的引用,代码示例

为派生类添加接口

继承自计数器类模板

统计创建过的某类的实例个数,可以通过在类中声明/定义一个静态成员变量实现,但这一功能并不需要在需要统计其创建实例个数的类中重复实现。

比如可以设计一个独立的计数器类,其它类以组合的方式,将计数器类作为本类的一个静态成员变量,也可以实现统计功能。另一种方法是继承计数器类模板,每个派生类所继承的基类(类模板)实例都是独一无二的,因此统计每个派生类的实例个数是互不影响的,代码示例

拷贝自身

面向对象编程中,如果需要添加(动态)多态接口,通常需要在基类中添加虚函数,同时也需要在所有派生类中添加相应的虚函数。考虑返回一个自身的拷贝的功能,在所有派生类中添加相应的虚函数处理会造成代码重复,这种情况下可以考虑在抽象基类中声明虚函数,CRTP派生类中相应虚函数实现会拷贝出一个派生自它的派生类的实例,即结合了动态多态与静态多态,代码示例

Expression Templates

表达式模板,待了解补充

注意事项

避免实际派生类与传递给基类(类模板)的模板参数不同

声明实际派生类时,传递给基类(类模板)的模板参数与实际派生类不同可能会通过编译,但也可能会造成隐避的bug或未定义错误。通过将基类(类模板)的构造函数声明为私有 + 声明派生类为基类友元,限制只有实际派生类可调用实例化的基类(类模板)类型的构造函数,从而触发编译错误。代码示例

基类(类模板)实例化

注意每个实例化出来的类模板类型都是不同的,可参考上述『计数器类模板』使用

统一存储派生类

由于每个实例化出来的类模板类型都不同,只有继承于某个抽象基类的CRTP派生类才能统一存储,其形式为存储抽象类型,如 std::vector<Abstract*>,可参考上述『拷贝自身』功能

参考

奇异递归模板模式(Curiously Recurring Template Pattern,CRTP)1
Curiously recurring template pattern wiki

posted on 2020-07-15 22:15  chenguang9239  阅读(744)  评论(0编辑  收藏  举报