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进行改造后, 会更好, 有兴趣的朋友可以试试。 我相信: 一次刻骨铭心的体验胜过千百次说教。