想想我们在遇到多语句分支时是不是首先想到的是 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++ 函数映射使用讲解的更多相关文章

  1. CUDA学习,第一个kernel函数及代码讲解

    前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...

  2. 洗礼灵魂,修炼python(25)--自定义函数(6)—从匿名函数进阶话题讲解中解析“函数式编程”

    匿名函数进阶 前一章已经说了匿名函数,匿名函数还可以和其他内置函数结合使用 1.map map():映射器,映射 list(map(lambda x:x*2,range(10))) #把range产生 ...

  3. map()函数映射

    map()函数(映射) pattern = "abba" str = "dog cat cat dog" res=str.split() print(list( ...

  4. 排列+函数映射——hdu6038好题

    /* 引理:[0,n-1]的排列,i向a[i]连边,那么每个数必定在一个环中 所以数组a可以分割成一些环,数组b也可以分割成一些环 先讨论a的一个环 a[a1]=a2 a[a2]=a3 a[a3]=a ...

  5. strpos、 strstr、 substr三个函数的对比讲解

    mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] ) 返回 needle 在 haystack 中首次出现的数字 ...

  6. ISNULL函数的深入讲解

    1.  标题有点夸张 2. 今天做统计查询员工加班时长的时,因为要将NULL值导入到decimal类型的字段中,但是发现导入之后得字段不属于NULL也不等于0,因此在接下来的运算过程中就很难继续进行, ...

  7. C#回调函数的简单讲解与应用例子(最简单讲解,大神绕道)

    本博客一直以来的宗旨就是:用最简单的方式讲清楚不复杂的问题. 因为本人也很菜所以也没法讲太复杂HHHHHH...... 所以如果哪天某个大神看到了觉得讲的有问题欢迎指出. 话不多说进入正题.. ——— ...

  8. tf.transpose函数的用法讲解

    tf.transpose函数中文意思是转置,对于低维度的转置问题,很简单,不想讨论,直接转置就好(大家看下面文档,一看就懂). tf.transpose(a, perm=None, name='tra ...

  9. C#累加器函数Aggregate用法 讲解

    Enumerable.Aggregate 扩展方法在System.Linq命名空间中,是Enumerable类的第一个方法(按字母顺序排名),但确是Enumerable里面相对复杂的方法. MSDN对 ...

随机推荐

  1. Django一对多,多对多操作

    简要说明 Django里面的数据库操作O2O&M2M,一般归属于models管理 使用场景 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了).//两个表的 ...

  2. 黑马程序员-- C语言执行过程及注意点

    通过对程序的逐步执行,了解C语言程序执行过程: 1.编写源文件即.c文件. #include <stdio.h> void play() { printf("hello worl ...

  3. nfs error

    mount -t nfs 10.173.55.154:/oradata /oradatamount: wrong fs type, bad option, bad superblock on 10.1 ...

  4. ubuntu 常用生产环境部署配置测试调优

    1,ubuntu monogdb 安装配置 2,ubuntu jdk1.7,tomcat7安装 3,ubuntu LAMP部署 4,mongodb 远程热备份及恢复 使用自带的mongodump和mo ...

  5. 纯JavaScript实现HTML5 Canvas六种特效滤镜

    纯JavaScript实现HTML5 Canvas六种特效滤镜  小试牛刀,实现了六款简单常见HTML5 Canvas特效滤镜,并且封装成一个纯 JavaScript可调用的API文件gloomyfi ...

  6. 【从零学习Python】Ubuntu14.10下Python开发环境配置

    1. 前言 近期在研究计算机视觉的一些算法,也刚開始接触linux,试着在ubuntu下用qt+openCV进行开发,感觉还行.可是Python作为在学术领域广为应用的高级解释性语言.其在计算机视觉的 ...

  7. js判断undefined类型,undefined,null,NaN的区别

    js判断undefined类型 今天使用showModalDialog打开页面,返回值时.当打开的页面点击关闭按钮或直接点浏览器上的关闭则返回值是undefined   所以自作聪明判断       ...

  8. JS年月日三级联动下拉框日期选择代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. 最近adt升级引起的问题

    其实也不知道是什么原因引起的,因为 之前安装的adt就是23.0.3的版本,但是最近突然创建安卓工程时出现了如下问题 D:\workspace\appcompat_v7\res\values-v21\ ...

  10. spring 加载配置文件的相关配置总结

    PropertyPlaceholderConfigurer      注意: Spring容器仅允许最多定义一个PropertyPlaceholderConfigurer(或<context:p ...