基于C++简易CRTP框架的嵌入式软件设计

[复制链接]
4062|11
 楼主| dong_abc 发表于 2013-8-27 21:54 | 显示全部楼层 |阅读模式
本帖最后由 dong_abc 于 2014-5-13 13:18 编辑

题记:有一条小径,它别有洞天 !

         近段时间在学习C++模板元编程。在学习C++ CRTP(递归模板)的时候,发现我只能用两个字来形容CRTP这种编程框架——“自由”,程序随性自由拓展,而丝毫不用改变之前原有的代码结构。
         
        1、 首先,简单描述一下C++的CRTP编程模式的使用。
  1. template <class T>
  2. struct base {   
  3.    void interface() {         
  4.    static_cast<T*>(this)->implementation();   
  5. }
  6.     void implementation();
  7.     ...
  8. };

  9. struct derived : base<T> {     
  10.     void implementation();
  11.      ...
  12. };
定义了一个基类模板 和 一个基类模板的派生类。
这两个类中都有 void implementation()函数,而且在基类的void interface()接口函数中用一个静态指针指向了implementation()函数。

实例化一个基类,并将派生类作为基类的参数。
  1. base<derived> base_t;
  2. base_t.implementation();
调用基类的implementation()成员函数,这时是调用的基类中的implementation()函数
还是派生类中的implementation()函数呢?

由于我们已经在derived派生类中定义了implementation
()函数,并且base类实例化时的参数指向了derived派生类。
所以base_t.implementation()调用的是派生类derived中的成员函数implementation
()。

如果派生类derived中没有定义implementation
()成员函数,
那么base_t.implementation()调用的是基类base中的成员函数implementation()。

因此,base类模板既可以调用当前的成员函数,还可以调用未来(派生类)的成员函数。
此特性称为“静态多态”,CRTP即使实现一种静态的多态效应。

       2、上面已经描述了CRTP的基本使用。现在我们来做一个基于单片机的小项目,这里使用的新唐的NU_Tiny-EVB_120和 keil开发环境。本项目是一个CO探测器,其工作流程非常简单。
探测器自检初始化 ---> 传感器检测当前环境CO含量并发出状态警告 ---> 进入低功耗模式 ---> 30秒后唤醒单片机,传感器再次检测当前环境CO含量并发出状态警告 ---> 进入低功耗模式 ...以此循环。
先给出基于CRTP的基本框架。
  1. //detector.h
  2. #ifndef __Detector_H__
  3. #define __Detector_H__
  4. #include "routine.h"
  5. template<typename T>
  6. struct detector {   
  7.      void fun() {
  8.      static_cast<T*>(this)->detector_init(0,"__DATE__");
  9.      for(;;){
  10.         static_cast<T*>(this)->detector_poll();
  11.         static_cast<T*>(this)->power_down();
  12.      }
  13. }
  14.     void detector_poll() {
  15.         while( static_cast<T*>(this)->power_scan() );
  16.         static_cast<T*>(this)->sensor_scan();
  17.         static_cast<T*>(this)->danger_warn();
  18.         static_cast<T*>(this)->dev_state();
  19. }
  20.    
  21.     void detector_init(int, char*);
  22.     int power_scan();
  23.     void power_down();
  24.     void danger_warn();
  25.     void dev_state();
  26.     void sensor_scan();   
  27. };

  28. template<typename T>
  29. void detector<T>::detector_init(int, char*) { }
  30. template<typename T>
  31. void detector<T>::power_down() { }
  32. template<typename T>
  33. int detector<T>::power_scan() {return 0;}
  34. /*xx厂家传感器*/
  35. template<typename T>
  36. void detector<T>::sensor_scan()
  37. {
  38.     routine_tt.io();//传感器扫描用翻转io来指示
  39. }
  40. template<typename T>
  41. void detector<T>::danger_warn() {  }
  42. template<typename T>
  43. void detector<T>::dev_state() {}

  44. /*----------------------------------------------------------------------------*/
  45. /*yy厂家传感器*/
  46. struct detector_a:detector<detector_a> {
  47. /*void sensor_scan()
  48. {
  49.     routine_tt.io();//传感器扫描用翻转io来指示
  50. }*/
  51. };
  52. #endif

  53. //main.cpp
  54. #include"detector.h"
  55. int main (void)
  56. {
  57.    __enable_irq();   
  58.    detector<detector_a> co_star;
  59.    co_star.fun();   
  60.    while(1)
  61.    {
  62.    }
  63. }

为了方便阅读,我删除了函数中具体的内容,只留下了一个最小框架。

  1. detector<detector_a> co_star;
  2. co_star.fun();
主函数中实例化了一个探测器co_star模板类,并且参数指向了detector模板的派生类detector_a,
由于我们使用的传感器类型较多,每个厂家,每个型号 的传感器的工作方式又可能不尽相同。
所以我在detector模板中预留了一种传感器(xx厂家的传感器),其扫描方式为detector<T>::sensor_scan()。

其后因市场原因,又需要使用yy厂家的传感器,所以我在detector模板的基础上派生了一个detector_a类,
同样定义yy的扫描方式为sensor_scan(),只是在detector实例化的时候,将参数指向了detector_a .
  1. /*yy厂家传感器*/
  2. struct detector_a:detector<detector_a>{
  3. void sensor_scan()
  4. {
  5.     routine_tt.io();//传感器扫描用翻转io来指示  
  6. }
所以主函数中co_star.fun()调用的detector<detector_a>::sensor_scan()其实是指向了yy厂家传感器的扫描方式
detector_a::sensor_scan()。

这里不仅仅传感器扫描可以通过CRTP来拓展,从fun() 到 detector_poll() 到 sensor_scan() 全都可以通过CRTP的静态多态效应来拓展/重构。
  1. struct detector_a:detector<detector_a>{
  2. void fun()
  3. {
  4. ...  
  5. }

  6. struct detector_a:detector<detector_a>{
  7. void detector_poll()
  8. {
  9. ...  
  10. }
从整个框架到一个内部函数都可用这种机制来拓展/重构,其可拓展的粒度可以是一个最小的函数调用。现在你可否体会到C++ CRTP模式的程序拓展呢?
本帖测试源代码也上传至此,具体的函数实现被我删掉了,仅以一个io翻转来做演示,请见谅。


如果您还想深入了解CRTP框架的嵌入式软件设计,可以看看john_lee老师的课程记录
https://bbs.21ic.com/icview-577248-1-1.html

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

参与人数 1威望 +4 收起 理由
john_lee + 4 很给力!

查看全部评分

airwill 发表于 2013-8-28 06:26 | 显示全部楼层
非常支持。
看来c++ 进入嵌入式系统,也具有很强的优势。
很想找时间也来玩一玩
diweo 发表于 2013-8-28 08:04 | 显示全部楼层
确实很有吸引力
 楼主| dong_abc 发表于 2013-8-28 12:35 | 显示全部楼层
airwill 发表于 2013-8-28 06:26
非常支持。
看来c++ 进入嵌入式系统,也具有很强的优势。
很想找时间也来玩一玩 ...

恩,舍得花时间玩的人不多。
后续我还会发一些关于元编程的嵌入式应用。
 楼主| dong_abc 发表于 2013-8-28 12:45 | 显示全部楼层
本帖最后由 dong_abc 于 2014-5-13 12:04 编辑

元编程与传统编程方法完全不一样。元程序是在编译的时候解析,通过摸板实例化来组合生成程序代码,其性能丝毫不比C代码差!
 楼主| dong_abc 发表于 2013-8-28 21:24 | 显示全部楼层
本帖最后由 dong_abc 于 2014-5-13 13:19 编辑

C++ CRTP ...... !
......
sedatefire 发表于 2013-8-31 22:09 | 显示全部楼层
lua,不知大家有何看法?

评论

好像是个脚本相关的,没接触过。  发表于 2013-11-2 19:19
dirtwillfly 发表于 2013-9-1 08:17 | 显示全部楼层
没玩过,关注下。难道以后嵌入式开发也逐渐由C发展到C++
xd54622 发表于 2013-9-2 19:29 | 显示全部楼层
关注一下
 楼主| dong_abc 发表于 2013-11-2 17:02 | 显示全部楼层
话说CRTP应该算是我目前所见过建设代码架构最好的方式之一 --------简洁、灵活、高效。
 楼主| dong_abc 发表于 2013-11-4 12:38 | 显示全部楼层
接上:
最重要的是它不依赖任何第三方组件。
限量_个性。 发表于 2013-11-4 13:09 | 显示全部楼层
最近也在C++,跟楼楼后面学两招~~:lol:lol
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:此id已冬眠...

43

主题

5073

帖子

22

粉丝
快速回复 在线客服 返回列表 返回顶部