注册与回调

news2024/11/25 22:20:24

C++ 再谈谈注册(本质是建立映射)与回调

  在之前的博文中, 我们探讨过映射的重要作用, 请直接看:http://blog.csdn.net/stpeace/article/details/39452203, 在那篇文章中, 我们是用STL中的map来做的, map建立的是key-value映射, 在本文中, 我们自己来建立映射, 并讨论一个更为复杂的程序, 顺便再次复习一下注册与回调。

注册与回调? 有那么复杂么?没有必要过多地扯了, 直接上代码:

复制代码

  1 #include <iostream>
  2 #include <vector>
  3 using namespace std;
  4  
  5 // 前向声明
  6 class BasicMod;
  7  
  8  
  9 //类函数指针类型
 10 typedef void (BasicMod:: *PFun)(const char* pParaName); 
 11  
 12  
 13 // 映射结点
 14 typedef struct
 15 {
 16     BasicMod *pMod;
 17     char szParaName[1024];
 18     PFun operTypeOne;
 19     PFun operTypeTwo;
 20     PFun operTypeThree;
 21 }MyMap;
 22  
 23  
 24 // 用全局的g_pv保存结点指针
 25 vector<MyMap *> g_pv;
 26  
 27  
 28 // 执行类, 提供注册, 查找接口, 并执行回调操作
 29 class Do
 30 {
 31 public:
 32     // 单例
 33     static Do *getInstance()
 34     {
 35         static Do *p = NULL;
 36         if(NULL == p)
 37         {
 38             p = new Do;
 39         }
 40  
 41         return p;
 42     }
 43  
 44     // 注册接口
 45     void regNode(BasicMod *pb, MyMap *pmap, int i)
 46     {
 47         MyMap *p = new MyMap;
 48         p->pMod = pb;
 49         memset(p->szParaName, 0, sizeof(p->szParaName));
 50         strncpy(p->szParaName, (pmap + i)->szParaName, sizeof(p->szParaName) - 1);
 51         p->operTypeOne = (pmap + i)->operTypeOne;
 52         p->operTypeTwo = (pmap + i)->operTypeTwo;
 53         p->operTypeThree = (pmap + i)->operTypeThree;
 54  
 55         g_pv.push_back(p);
 56     }
 57  
 58     // 查找接口
 59     MyMap *findNode(const char *pParaName)
 60     {
 61         int n = g_pv.size();
 62         int i = 0;
 63         for(i = 0; i < n; i++)
 64         {
 65             if(0 == strcmp(g_pv[i]->szParaName, pParaName))
 66             {
 67                 return g_pv[i];
 68             }
 69         }
 70  
 71         return NULL;
 72     }
 73  
 74     // 执行回调操作
 75     void exect(const char *pParaName)
 76     {
 77         MyMap *p = findNode(pParaName);
 78         if(NULL != p && NULL != p->pMod)
 79         {
 80             ((p->pMod)->*(p->operTypeOne))(pParaName);
 81             ((p->pMod)->*(p->operTypeTwo))(pParaName);
 82             ((p->pMod)->*(p->operTypeThree))(pParaName);
 83         }
 84     }
 85 };
 86  
 87  
 88 // 基类
 89 class BasicMod
 90 {
 91 public:
 92     void reg(BasicMod *pm, MyMap *p, int i)
 93     {
 94         Do::getInstance()->regNode(pm, p, i);    
 95     }
 96 };
 97  
 98  
 99 // 格式化
100 #define TOGETHER(mod, name, f1, f2, f3) {NULL, name, (PFun)(&mod::f1), (PFun)(&mod::f2), (PFun)(&mod::f3)}
101  
102  
103 // 模块1
104 class Mod1 : public BasicMod
105 {
106 public:
107     static Mod1* getInstance()
108     {
109         static Mod1* p = NULL;
110         if(NULL == p)
111         {
112             p = new Mod1;
113         }
114  
115         return p;
116     }
117  
118     // 模块1的初始化
119     void init()
120     {
121         MyMap mapArr[] = 
122         {
123             TOGETHER(Mod1, "cpu", fun1Cpu, fun2Cpu, fun3Cpu),
124         };
125  
126         int n = sizeof(mapArr) / sizeof(mapArr[0]);
127         int i = 0;
128         for(i = 0; i < n; i++)
129         {
130             // 注册
131             reg(getInstance(), mapArr, i);
132         }
133     }
134  
135     // 提供回调接口
136     void fun1Cpu(const char *pParaName)
137     {
138         cout << "mod1, pParaName is " << pParaName << endl;
139     }
140  
141     // 提供回调接口
142     void fun2Cpu(const char *pParaName)
143     {
144         cout << "mod1, pParaName is " << pParaName << endl;
145     }
146  
147     // 提供回调接口
148     void fun3Cpu(const char *pParaName)
149     {
150         cout << "mod1, pParaName is " << pParaName << endl;
151     }
152 };
153  
154  
155 class Mod2 : public BasicMod
156 {
157 public:
158     static Mod2* getInstance()
159     {
160         static Mod2* p = NULL;
161         if(NULL == p)
162         {
163             p = new Mod2;
164         }
165  
166         return p;
167     }
168  
169     void init()
170     {
171         MyMap mapArr[] = 
172         {
173             TOGETHER(Mod2, "flash", fun1Flash, fun2Flash, fun3Flash),
174         };
175  
176         int n = sizeof(mapArr) / sizeof(mapArr[0]);
177         int i = 0;
178         for(i = 0; i < n; i++)
179         {
180             reg(getInstance(), mapArr, i);
181         }
182     }
183  
184     void fun1Flash(const char *pParaName)
185     {
186         cout << "mod2, pParaName is " << pParaName << endl;
187     }
188  
189     void fun2Flash(const char *pParaName)
190     {
191         cout << "mod2, pParaName is " << pParaName << endl;
192     }
193  
194     void fun3Flash(const char *pParaName)
195     {
196         cout << "mod2, pParaName is " << pParaName << endl;
197     }
198 };
199  
200  
201 int main()
202 {
203     // 模块初始化
204     Mod1::getInstance()->init();
205     Mod2::getInstance()->init();
206  
207     // 执行操作
208     Do::getInstance()->exect("cpu");
209     Do::getInstance()->exect("flash");
210     Do::getInstance()->exect("mem");
211  
212     return 0;
213 }

复制代码

程序的结果为:

mod1, pParaName is cpu
mod1, pParaName is cpu
mod1, pParaName is cpu
mod2, pParaName is flash
mod2, pParaName is flash
mod2, pParaName is flash

我们也可以对上述程序作一下等价变换, 得到:

复制代码

  1 #include <iostream>
  2 #include <vector>
  3 using namespace std;
  4  
  5 // 前向声明
  6 class BasicMod;
  7  
  8  
  9 //类函数指针类型
 10 typedef void (BasicMod:: *PFun)(const char* pParaName); 
 11  
 12  
 13 // 映射结点
 14 typedef struct
 15 {
 16     BasicMod *pMod;
 17     char szParaName[1024];
 18     PFun operTypeOne;
 19     PFun operTypeTwo;
 20     PFun operTypeThree;
 21 }MyMap;
 22  
 23  
 24 // 用全局的g_pv保存结点指针
 25 vector<MyMap *> g_pv;
 26  
 27  
 28 // 执行类, 提供注册, 查找接口, 并执行回调操作
 29 class Do
 30 {
 31 public:
 32     // 单例
 33     static Do *getInstance()
 34     {
 35         static Do *p = NULL;
 36         if(NULL == p)
 37         {
 38             p = new Do;
 39         }
 40  
 41         return p;
 42     }
 43  
 44     // 注册接口
 45     void regNode(BasicMod *pm, const char *pParaName, PFun one, PFun two, PFun three)
 46     {
 47         MyMap *p = new MyMap;
 48         p->pMod = pm;
 49         memset(p->szParaName, 0, sizeof(p->szParaName));
 50         strncpy(p->szParaName, pParaName, sizeof(p->szParaName) - 1);
 51         p->operTypeOne = one;
 52         p->operTypeTwo = two;
 53         p->operTypeThree = three;
 54  
 55         g_pv.push_back(p);
 56     }
 57  
 58     // 查找接口
 59     MyMap *findNode(const char *pParaName)
 60     {
 61         int n = g_pv.size();
 62         int i = 0;
 63         for(i = 0; i < n; i++)
 64         {
 65             if(0 == strcmp(g_pv[i]->szParaName, pParaName))
 66             {
 67                 return g_pv[i];
 68             }
 69         }
 70  
 71         return NULL;
 72     }
 73  
 74     // 执行回调操作
 75     void exect(const char *pParaName)
 76     {
 77         MyMap *p = findNode(pParaName);
 78         if(NULL != p && NULL != p->pMod)
 79         {
 80             ((p->pMod)->*(p->operTypeOne))(pParaName);
 81             ((p->pMod)->*(p->operTypeTwo))(pParaName);
 82             ((p->pMod)->*(p->operTypeThree))(pParaName);
 83         }
 84     }
 85 };
 86  
 87  
 88 // 基类
 89 class BasicMod
 90 {
 91 public:
 92     void reg(const char *pParaName, PFun one, PFun two, PFun three)
 93     {
 94         Do::getInstance()->regNode(this, pParaName, one, two, three);    
 95     }
 96 };
 97  
 98  
 99 // 格式化
100 #define TOGETHER(mod, name, f1, f2, f3) {NULL, name, (PFun)(&mod::f1), (PFun)(&mod::f2), (PFun)(&mod::f3)}
101  
102  
103 // 模块1
104 class Mod1 : public BasicMod
105 {
106 public:
107     static Mod1* getInstance()
108     {
109         static Mod1* p = NULL;
110         if(NULL == p)
111         {
112             p = new Mod1;
113         }
114  
115         return p;
116     }
117  
118     // 模块1的初始化
119     void init()
120     {
121         MyMap mapArr[] = 
122         {
123             TOGETHER(Mod1, "cpu", fun1Cpu, fun2Cpu, fun3Cpu),
124         };
125  
126         int n = sizeof(mapArr) / sizeof(mapArr[0]);
127         int i = 0;
128         for(i = 0; i < n; i++)
129         {
130             // 注册
131             reg(mapArr[i].szParaName, mapArr[i].operTypeOne, mapArr[i].operTypeTwo, mapArr[i].operTypeThree);
132         }
133     }
134  
135     // 提供回调接口
136     void fun1Cpu(const char *pParaName)
137     {
138         cout << "mod1, pParaName is " << pParaName << endl;
139     }
140  
141     // 提供回调接口
142     void fun2Cpu(const char *pParaName)
143     {
144         cout << "mod1, pParaName is " << pParaName << endl;
145     }
146  
147     // 提供回调接口
148     void fun3Cpu(const char *pParaName)
149     {
150         cout << "mod1, pParaName is " << pParaName << endl;
151     }
152 };
153  
154  
155 class Mod2 : public BasicMod
156 {
157 public:
158     static Mod2* getInstance()
159     {
160         static Mod2* p = NULL;
161         if(NULL == p)
162         {
163             p = new Mod2;
164         }
165  
166         return p;
167     }
168  
169     void init()
170     {
171         MyMap mapArr[] = 
172         {
173             TOGETHER(Mod2, "flash", fun1Flash, fun2Flash, fun3Flash),
174         };
175  
176         int n = sizeof(mapArr) / sizeof(mapArr[0]);
177         int i = 0;
178         for(i = 0; i < n; i++)
179         {
180             reg(mapArr[i].szParaName, mapArr[i].operTypeOne, mapArr[i].operTypeTwo, mapArr[i].operTypeThree);
181         }
182     }
183  
184     void fun1Flash(const char *pParaName)
185     {
186         cout << "mod2, pParaName is " << pParaName << endl;
187     }
188  
189     void fun2Flash(const char *pParaName)
190     {
191         cout << "mod2, pParaName is " << pParaName << endl;
192     }
193  
194     void fun3Flash(const char *pParaName)
195     {
196         cout << "mod2, pParaName is " << pParaName << endl;
197     }
198 };
199  
200  
201 int main()
202 {
203     // 模块初始化
204     Mod1::getInstance()->init();
205     Mod2::getInstance()->init();
206  
207     // 执行操作
208     Do::getInstance()->exect("cpu");
209     Do::getInstance()->exect("flash");
210     Do::getInstance()->exect("mem");
211  
212     return 0;
213 }

复制代码

我们看到, 上述程序建立了一个name对于{f1, f2, f3}的映射, 适用范围更广。

而且, 以后如果再加字段, 程序猿只需要注意三处即可: 1. 增加initialize函数中数组中的项(增加映射);2. 在类中实现回调接口(增加回调接口); 3.在main中启动调用(启动执行)。

当然啦, 如果要增加模块3, 那也是很easy的。

反思一下:我突然发现, 我把上面的程序写复杂了, 其实, 也可以用STL map建立name到f1, f2, f3的映射, 此时, 要把{f1, f2, f3}看成一个整体, 上述程序用STL map进行改造后, 会更好, 有兴趣的朋友可以试试。 我相信: 一次刻骨铭心的体验胜过千百次说教。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1317213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营Day1 | 704.二分查找、27.移除元素

LeetCode 704 二分查找 题目链接&#xff1a;704.二分查找 本题思路&#xff1a;本题题目写的是二分查找&#xff0c;所以我们用到的算法肯定也是二分查找&#xff0c;需要定义 3个变量。 l: 从数组的下标0开始 r: 数组长度 - 1 mid&#xff1a;&#xff08;l r&#xff09;…

AUTOSAR组织引入了Rust语言的原因是什么?有哪些好处?与C++相比它有什么优点?并推荐一些入门学习Rust语言链接等

AUTOSAR(汽车开放系统架构)是一个由汽车制造商、供应商和其他来自电子、半导体和软件行业的公司组成的全球发展伙伴关系,自2003年以来一直致力于为汽车行业开发和引入开放、标准化的软件平台。 AUTOSAR 最近宣布成立一个新的工作组,用于探索在汽车软件中使用 Rust 编程语言…

【网络安全】网络防护之旅 - 点燃网络安全战场的数字签名烟火

​ &#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《网络安全之道 | 数字征程》⏰墨香寄清辞&#xff1a;千里传信如电光&#xff0c;密码奥妙似仙方。 挑战黑暗剑拔弩张&#xff0c;网络战场誓守长。 ​ 目录 &#x1f608;1. 初识…

2023年总结,讲讲我的故事吧,十年

文章目录 2023前十年后十年 周末&#xff0c;本该是提升自己的最好时机&#xff0c;也该是出去玩的大好时光&#xff0c;但是毫无意外的&#xff0c;在家躺了一天&#xff0c;单纯的有点累。 2023年&#xff0c;发生了好多事情&#xff0c;又好像没发生几件事&#xff0c;可能毕…

录制第一个jmeter性能测试脚本2(http协议)_图书管理系统

我们手工编写了一个测试计划&#xff0c;现在我们通过录制的方式来实现那个测试计划。也就是说‘’测试计划目标和上一节类似&#xff1a;让5个用户在2s内登录图书管理系统&#xff0c;然后进入 页面进行查看。 目录 欢迎访问我的免费课程 PPT、安装包、视频应有尽有&#xff…

Linux Shell——输入输出重定向

输入输出重定向 1. 重定向输入2. 重定向输出 总结 最近学习了shell语法&#xff0c;总结一下关于输入输出重定向的知识。 一般情况下&#xff0c;linux每次执行命令其实都会打开三个文件&#xff0c;分别是&#xff1a; 标准输入stdin 文件描述符为0 标准输出stdout 文件描述符…

mysql8支持远程访问

上面的localhost要改为%号就打开了远程访问 ALTER USER root% IDENTIFIED WITH mysql_native_password BY fengzi2141;

NSSCTF第16页(2)

[NSSRound#4 SWPU]1zweb(revenge) 查看index.php <?php class LoveNss{public $ljt;public $dky;public $cmd;public function __construct(){$this->ljt"ljt";$this->dky"dky";phpinfo();}public function __destruct(){if($this->ljt"…

Python将列表中的数据写入csv并正确解析出来

用Python做数据处理常常会将数据写到文件中进行保存&#xff0c;又或将保存在文件中的数据读出来进行使用。通过Python将列表中的数据写入到csv文件中很多人都会&#xff0c;可以通过Python直接写文件或借助pandas很方便的实现将列表中的数据写入到csv文件中&#xff0c;但是写…

C语言—小小圣诞树

这个代码会询问用户输入圣诞树的高度&#xff0c;然后根据输入的高度在控制台上显示相应高度的圣诞树。 #include <stdio.h>int main() {int height, spaces, stars;printf("请输入圣诞树的高度: ");scanf("%d", &height);spaces height - 1;st…

【MySQL】触发器trigger / 事件

文章目录 1. 触发器 trigger1.1 触发器命名1.2 new和old关键字1.3 案例&#xff1a;insert 触发器1.4 练习&#xff1a;delete 触发器1.5 查看触发器 show triggers1.6 使用触发器记录对表的操作 2 事件2.1 打开 / 关闭事件调度器2.2 创建事件 create event2.3 查看&#xff0c…

idea__SpringBoot微服务11——整合Druid数据源(新依赖)(新注解)

整合JDBC 一、导入依赖二、配置Druid————————创作不易&#xff0c;如觉不错&#xff0c;随手点赞&#xff0c;关注&#xff0c;收藏(*&#xffe3;︶&#xffe3;)&#xff0c;谢谢~~ 接着 第10的 新注解&#xff1a; ConfigurationProperties ConfigurationPropert…

流量分析基础

定义&#xff1a; 流量分析&#xff08;Traffic Analysis&#xff09;是指对网络流量数据进行分析和解释&#xff0c;以获得有关网络中通信的信息和情报。这种技术可以用于网络安全、网络管理和网络优化等领域。 网络流量包含了许多有关网络通信的细节信息&#xff0c;如源IP地…

【教3妹学编程-算法题】使用最小花费爬楼梯

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 3妹&#xff1a;2哥2哥&#xff0c;你有没有看到新闻&…

2023/12/17 初始化

普通变量&#xff08;int,float,double变量&#xff09;初始化&#xff1a; int a0; float b(0); double c0; 数组初始化&#xff1a; int arr[10]{0}; 指针初始化&#xff1a; 空指针 int *pnullptr; 被一个同类型的变量的地址初始化&#xff08;赋值&#xff09; int…

必要时进行保护性拷贝

保护性拷贝&#xff08;Defensive Copy&#xff09;是一种常见的编程实践&#xff0c;用于在传递参数或返回值时&#xff0c;创建副本以防止原始对象被意外修改。以下是一个例子&#xff0c;展示了何时进行保护性拷贝&#xff1a; mport java.util.ArrayList; import java.uti…

昇腾Profiling性能分析工具使用问题案例

昇腾Profiling性能分析工具用于采集和分析运行在昇腾硬件上的AI任务各个运行阶段的关键性能指标, 用户可根据输出的性能数据&#xff0c;快速定位软、硬件性能瓶颈&#xff0c;提升AI任务性能分析的效率。具体使用方法请参考&#xff1a; 本期分享几个关于Profiling性能分析工具…

Linux开发工具--vim

Linux开发工具--vim 一、vim的基本概念二、常见命令三、简单配置vim配置文件的位置常用配置选项&#xff0c;用来测试使用插件 一、vim的基本概念 vim编辑器&#xff0c;只负责写代码&#xff0c;vim是一款多模式的编辑器 vim的三种模式(其实有好多模式&#xff0c;目前掌握这…

patchless amsi学习(上)

传统的通过patch内存AmsiScanBuffer,这个网上有很多文章&#xff0c;而且相对也比较简单&#xff0c;这里就不再解释了&#xff0c;但是patch这个动作势必会有一定的敏感性&#xff0c;比如你需要修改关键位置内存属性。本文要讲的是无需patch的方式绕过amsi。 前置知识-硬件断…

wordpress:6.3的docker部署和k8s部署方式

wordpress:6.3的docker部署 一.docker部署mysql5.7数据库 docker pull mysql:5.7 mkdir -p /data/mysql/data /data/mysql/logs /data/mysql/conf touch /data/mysql/conf/my.cnf docker run --restartalways -p 13306:3306 --name mysql -v /data/mysql/conf:/etc/mysql/con…