网站首页 > 博客文章 正文
最近由于开发工作的需要,项目引入了boost::statechart的状态机,它大量了引用了CRTP, 它的全称是Curiously Recurring Template Pattern,奇异递归模板模式,C++模板编程中很常用的一种用法。那么它神奇的地方到底在哪里呢,接下来就一一来揭开它神秘的面纱。
一、奇异递归模板模式的简介
奇异递归模板模式的基本思想要点是:派生类要作为基类的模板参数。它是C++模板编程中常用的手法。理解它之后,学习模板编程过程中也会事半功倍,而不会觉得云里雾里的。
二、奇异递归模板模式的基本格式
奇异递归模板模式的基本格式如下:JCrtpDerived继承JCrtpBase,并且JCrtpDerived作为基类JCrtpBase的模板参数。通过这样的方式,基类就可以使用子类的方法。并且不需要使用到虚函数,一定程度上减少程序的开销。
三、奇异递归模板模式的入门
从上面的给出的奇异递归模板模式的基本格式中可以看出,子类是作为基类的模板参数,但是如果传递给基类的模板参数不是基类的子类,那就会造成混乱错误。如下图所示,JCrtpDerived2子类继承了基类JCrtpBase,但是传递给基类的模板参数不是JCrtpDerived2。
那么如何解决上面的问题呢,可以将基类的默认构造函数设置为私有,并且模板参数T设置为基类的友元。通过这样的方式,基类的构造函数只能由模板参数T调用。当创建JCrtpDerived2子类对象的时候,会调用基类的构造函数,而这时候发现JCrtpDerived2不是基类的友元,那么就无法调用基类构造函数而出错。
调用运行JCrtpDerived2,就会出现错误
四、奇异递归模板模式的应用场景
1、静态多态
奇异递归模板模式可以实现静态多态的效果,顾名思义,就是有多态的特性,但是不需要使用虚函数,是编译的时候确定,因此,能够减少运行时的开销。接下来就来看看两个示例。
基类JCrtpBase实现函数Do,该函数内部对象通过static_cast转换为模版参数对象,模板参数对象再调用对应的实现函数,而模板参数对象由子类来实现。
调用运行的效果如下所示,从中可以看出,对象调用基类的函数,而基类函数实际上又去调用子类的函数DoSomething。基于这样的思想,我们可以将通用的逻辑放在基类Do中实现,而不同的放到对应的子类函数DoSomething实现。
这样需要注意的一点是,如果子类再被其他子类继承,那么其他子类就不能按照上面的方式实现。具体可以看下示例:JCrtpSub子类再继承JCrtpDerived1。
调用运行的效果如下所示,JCrtpSub调用基类的函数Do,但是运行没有调用到JCrtpSub类自身的函数DoSomething。
上面的例子是子类调用基类函数,由基类再转换调用子类函数,效果类似于策略模式。下面将要说明的例子,更像多态特性,但是不需要虚函数。基类和子类都实现相同的函数DoSomething
然后实现模板方法,该方法入参为基类JCrtpBase的引用,内部调用基类函数DoSomething。
调用运行效果如下,向模板方法传递不同的子类,调用对应子类的函数。
2、boost::statechart状态机
Boost.Statechart大量使用了CRTP, 派生类必须作为第一个参数传递给所有基类模板,Boost.Statechart状态机后续考虑作为一个专题来研究讨论。
3、std::enable_shared_from_this特性
C++的特性enable_shared_from_this通常是用于在当你要返回一个被shared_ptr管理的对象。JObj继承enable_shared_from_this,并且JObj作为参数模板传递给enable_shared_from_this,这里就运用到了CRTP。
正确的调用方式,JObj是被shared_ptr管理,因此,如果要获取对象,那么JObj需要继承enable_shared_from_this。
五、总结
到这里,奇异递归模板模式已经基本讲解完成,我们首先介绍了它的基本格式,使用注意要点,然后重点讲解了它的应用场景,包括静态多态、boost::statechart状态机、std::enable_shared_from_this特性。理解了奇异递归模板模式,不但有利于模板编程的学习,而且对于以后应用的开发也是有好处的。
猜你喜欢
- 2024-10-01 操作系统 : 按优先数调度算法实现处理器调度(C++)
- 2024-10-01 c++ 疑难杂症(13) allocator(c++ catch all exception)
- 2024-10-01 百度C++工程师的那些极限优化(内存篇)
- 2024-10-01 C++20 香不香?从四大新特性看起(c++20支持)
- 2024-10-01 用C++11打造智能观察者模式:详解实现步骤完整示例代码
- 2024-10-01 网络编程:手绘TCP状态机(tcp状态转换图详解)
- 2024-10-01 C++为什么不提倡使用单例模式?(c++为什么不用printf)
- 2024-10-01 智能系统机器人!C++实现三阶魔方自动求解程序源码
- 2024-10-01 ChaosBlade 发布对 C++ 应用混沌实验的支持
- 2024-10-01 C/C++编程笔记:C++智能指针及其类型的介绍!重点分析
你 发表评论:
欢迎- 07-08Google Cloud Platform 加入支持 Docker 的容器引擎
- 07-08日本KDDI与Google Cloud 签署合作备忘录,共探AI未来
- 07-08美国Infoblox与Google Cloud合作推出云原生网络和安全解决方案
- 07-08GoogleCloud为Spanner数据库引入HDD层,将冷存储成本降低80%
- 07-08谷歌推出Cloud Dataproc,缩短集群启动时间
- 07-08Infovista与Google Cloud携手推进射频网络规划革新
- 07-08比利时Odoo与Google Cloud建立增强合作,扩大全球影响力
- 07-08BT 和 Google Cloud 通过 Global Fabric 加速 AI 网络
- 最近发表
-
- Google Cloud Platform 加入支持 Docker 的容器引擎
- 日本KDDI与Google Cloud 签署合作备忘录,共探AI未来
- 美国Infoblox与Google Cloud合作推出云原生网络和安全解决方案
- GoogleCloud为Spanner数据库引入HDD层,将冷存储成本降低80%
- 谷歌推出Cloud Dataproc,缩短集群启动时间
- Infovista与Google Cloud携手推进射频网络规划革新
- 比利时Odoo与Google Cloud建立增强合作,扩大全球影响力
- BT 和 Google Cloud 通过 Global Fabric 加速 AI 网络
- NCSA和Google Cloud合作开发AI驱动的网络防御系统,加强泰国网络空间的安全性
- SAP将在沙特阿拉伯 Google Cloud 上推出BTP服务
- 标签列表
-
- ifneq (61)
- 字符串长度在线 (61)
- googlecloud (64)
- messagesource (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)