C++ 函数映射使用讲解
想想我们在遇到多语句分支时是不是首先想到的是 switc case 和 if else if ...
这2种方式在编码方面确实简单少,但是当分支达到一定数量后,特别是分支内部有嵌套大段代码或者再嵌套分支,
代码会显得异常臃肿,十分难以维护,对于if else if 语句过多的分支带来过多的判定句,势必会影响效率。
3种替代方法简述:
1.使用map,需要构建树和节点,比数组的方式消耗更多的内存,查询时间复杂度为Log(N),但扩展起来方便。
2.使用数组,查询直接索引定位, 一般来讲我们是连续的初始化数组,也就意味索引(type_func)到函数的映射要连续,
所以使用数组索引在扩展上来讲:例如增删元素是稍微麻烦点的。
3.使用C++的特性---抽象继承来实现,本文只讲前2种的使用,这种方式以后再补充。
我比较喜欢用代码结合实际来讲解,下面我将以一段事例代码来讲解如何使用这几种映射:
// 动物会一些动作
enum type_func
{
type_begin = -1,
type_eat,
type_sleep,
type_walk,
type_run,
type_smile,
type_cry,
type_jump, type_max_size,
}; class CAnimal
{
public:
typedef int (CAnimal::*ptr_func)(bool); protected: static map<type_func,ptr_func> s_map;
static ptr_func s_array[type_max_size]; public:
CAnimal()
{
memset(s_array,0,sizeof(s_array));
Init();
} // 需要映射函数的返回值 和 参数必须 统一
int eat (bool= true) { return printf("eatn") ,1; }
int sleep (bool= true) { return printf("sleepn"),1; }
int walk (bool= true) { return printf("walkn") ,1; }
int run (bool= true) { return printf("runn") ,1; }
int smile (bool= true) { return printf("smilen"),1; }
int cry (bool= true) { return printf("cryn") ,1; }
int jump (bool= true) { return printf("jumpn") ,1; } // 初始化
void Init ()
{
s_map[type_eat] = &CAnimal::eat;
s_map[type_sleep] = &CAnimal::sleep;
s_map[type_walk] = &CAnimal::walk;
s_map[type_run] = &CAnimal::run;
s_map[type_smile] = &CAnimal::smile;
s_map[type_cry] = &CAnimal::cry;
s_map[type_jump] = &CAnimal::jump; s_array[type_eat] = &CAnimal::eat;
s_array[type_sleep] = &CAnimal::sleep;
s_array[type_walk] = &CAnimal::walk;
s_array[type_run] = &CAnimal::run;
s_array[type_smile] = &CAnimal::smile;
s_array[type_cry] = &CAnimal::cry;
s_array[type_jump] = &CAnimal::jump;
} // 一般做法是switc case 或者 if else...
// 其实这里看起来还不算糟糕,一方面这里我把每个模块内容都封装到相应函数了
// 分支内部才会看起来相对简洁,实际编码中可能就不是你现在所看到的方式。
void Process (type_func type)
{
switch (type)
{
case type_eat: eat(); break;
case type_sleep: sleep(); break;
case type_walk: walk(); break;
case type_run: run(); break;
case type_smile: smile(); break;
case type_cry: cry(); break;
case type_jump: jump(); break;
}
} // 很熟悉的感觉吧! :)
void Process2(type_func type)
{
if (type_eat == type)
{
eat();
}
else if (type_sleep == type)
{
sleep();
}
else if (type_walk == type)
{
walk();
}
else if (type_run == type)
{
run();
}
else if (type_smile == type)
{
smile();
}
else if (type_cry == type)
{
cry();
}
else if (type_jump == type)
{
jump();
}
} // 使用map 映射
void ProcessByUseMap(int key, bool val)
{
map<type_func,ptr_func>::iterator it = s_map.find((type_func)key);
if (it != s_map.end())
{
ptr_func pFun = it->second;
if (pFun)
(this->*pFun)(val);
}
} // 使用数组 映射
void ProcessByUseArray(int key, bool val)
{
// 数组
if (type_begin < key && type_max_size > key)
{
ptr_func pFun = s_array[key];
if (pFun)
(this->*pFun)(val);
}
} // 使用map 映射
int operator[] (int key)
{
map<type_func,ptr_func>::iterator it = s_map.find((type_func)key);
if (it != s_map.end())
{
ptr_func pFun = it->second;
if (pFun) return (this->*pFun)(false);
}
return NULL;
} // 使用数组 映射
int operator() (int key,bool val)
{
if (type_begin < key && type_max_size > key)
{
ptr_func pFun = s_array[key];
if (pFun) return (this->*pFun)(val);
}
return NULL;
} }; map<type_func, CAnimal::ptr_func> CAnimal::s_map;
CAnimal::ptr_func CAnimal::s_array[type_max_size]; //////////////////////////////////////////////////////////////////////////
// 非成员函数
void func_eat(int = 0) { }
void func_run(int = 0) { }
void func_walk(int =0) { }
void func_cry(int = 0) { } typedef void (*ptrFun)(int);
map<type_func,ptrFun> g_map;
ptrFun g_array[type_max_size]; int _tmain(int argc, _TCHAR* argv[])
{ //////////////////////////////////////////////////////////////////////////
// 为了便于说明,下面代码不做安全检查 // 非成员函数映射2种用法
// init
g_map[type_eat] = func_eat;
g_map[type_run] = func_run;
g_map[type_walk] = func_walk;
g_map[type_cry] = func_cry; g_array[type_eat] = func_eat;
g_array[type_run] = func_run;
g_array[type_walk] = func_walk;
g_array[type_cry] = func_cry; // using
g_map[type_eat](1);
g_map[type_run](2);
g_map[type_walk](3);
g_map[type_cry](4); g_array[type_eat](1);
g_array[type_run](2);
g_array[type_walk](3);
g_array[type_cry](4); //////////////////////////////////////////////////////////////////////////
// 成员函数映射使用 CAnimal Dog; Dog.Process(type_eat);
Dog.ProcessByUseMap(type_run,true);
Dog.ProcessByUseArray(type_cry,false);
Dog[type_walk];
Dog(type_sleep,true);
Dog(type_run,false); return 1;
}
C++ 函数映射使用讲解的更多相关文章
- CUDA学习,第一个kernel函数及代码讲解
前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...
- 洗礼灵魂,修炼python(25)--自定义函数(6)—从匿名函数进阶话题讲解中解析“函数式编程”
匿名函数进阶 前一章已经说了匿名函数,匿名函数还可以和其他内置函数结合使用 1.map map():映射器,映射 list(map(lambda x:x*2,range(10))) #把range产生 ...
- map()函数映射
map()函数(映射) pattern = "abba" str = "dog cat cat dog" res=str.split() print(list( ...
- 排列+函数映射——hdu6038好题
/* 引理:[0,n-1]的排列,i向a[i]连边,那么每个数必定在一个环中 所以数组a可以分割成一些环,数组b也可以分割成一些环 先讨论a的一个环 a[a1]=a2 a[a2]=a3 a[a3]=a ...
- strpos、 strstr、 substr三个函数的对比讲解
mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] ) 返回 needle 在 haystack 中首次出现的数字 ...
- ISNULL函数的深入讲解
1. 标题有点夸张 2. 今天做统计查询员工加班时长的时,因为要将NULL值导入到decimal类型的字段中,但是发现导入之后得字段不属于NULL也不等于0,因此在接下来的运算过程中就很难继续进行, ...
- C#回调函数的简单讲解与应用例子(最简单讲解,大神绕道)
本博客一直以来的宗旨就是:用最简单的方式讲清楚不复杂的问题. 因为本人也很菜所以也没法讲太复杂HHHHHH...... 所以如果哪天某个大神看到了觉得讲的有问题欢迎指出. 话不多说进入正题.. ——— ...
- tf.transpose函数的用法讲解
tf.transpose函数中文意思是转置,对于低维度的转置问题,很简单,不想讨论,直接转置就好(大家看下面文档,一看就懂). tf.transpose(a, perm=None, name='tra ...
- C#累加器函数Aggregate用法 讲解
Enumerable.Aggregate 扩展方法在System.Linq命名空间中,是Enumerable类的第一个方法(按字母顺序排名),但确是Enumerable里面相对复杂的方法. MSDN对 ...
随机推荐
- Servlet基础知识(四)——Servlet过滤器Filter
一.什么是过滤器: 政府大楼的安检保安,它既能对进入政府大楼的人员进行检查,只允许检查符合要求的进入:同时他也负责对出大楼的人进行检查,看他带出的东西是否符合要求. 同样的,Servlet中的过滤器既 ...
- Notepad++使用技法
Alt+H 隐藏行 Ctrl+Tab 实现在多个打开的窗口间切换 Ctrl+Shift+Q区块注释 Ctrl+K行注释(取消Ctrl+Shift+K) 文件 新建文件 Ctrl+N 打开文件 C ...
- bzoj 1088: [SCOI2005]扫雷Mine
题目链接 1088: [SCOI2005]扫雷Mine Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2525 Solved: 1495[Submi ...
- android-SQLite 和 Content
SQLite 游标(Cursor)相当于指向底层数据中结果集的指针,而不是提取和返回结果值的副本,是在结果集中对位置(行)进行控制的管理方式. moveToFirst:把游标移动到查询结果的第一行 m ...
- hdu 4545 魔法串 2013金山西山居创意游戏程序挑战赛——初赛(1)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4545 这题太坑了,小明的串可以任意删掉某个字符 这句话不知道大家是怎么理解的,我觉得应该是能够删除其中 ...
- java 键盘输入多种方法 .(转载)
一.java不像C中拥有scanf这样功能强大的函数,大多是通过定义输入输出流对象.常用的类有BufferedReader,Scanner. 实例程序: 1.利用 Scanner 实现从键盘读入int ...
- HDU 5818 Joint Stacks(左偏树)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5818 [题目大意] 给出两个栈A B(初始时为空),有三种操作: push.pop.merge. ...
- PendingIntent详解
Intent是一个意图,一个描述了想要启动一个Activity.Broadcast或是Service的意图.它主要持有的信息是它想要启动的组件(Activity.Broadcast或是Service) ...
- SQL Server索引进阶:第二级,深入非聚集索引
原文地址: Stairway to SQL Server Indexes: Level 2, Deeper into Nonclustered Indexes 本文是SQL Server索引进阶系列( ...
- KeCode对照表(键盘按键的获取)
KeyCode键盘对照表: http://www.cnblogs.com/furenjian/articles/2957770.html