欢迎来到代码驿站!

C代码

当前位置:首页 > 软件编程 > C代码

如何用c++表驱动替换if/else和switch/case语句

时间:2023-02-21 13:44:45|栏目:C代码|点击:

C++的表驱动法

目的:使用表驱动法,替换复杂的if/else和switch/case语句。

 一、常用示例

以switch为例,常用示例如下:

Funcition()
{
    switch (key)
    {
        case key1:
            statements 1;
            break;
        case key2:
            statements 2;
            break;
        ... 
        case keyn:
            statements n;
            break;
        default:
            break;
    }
}

 上述switch代码段,实际集成了3种类型逻辑:

1.    实现关键字的处理代码;
2.    将关键字与处理代码关联;
3.    以关键字选择分支,执行处理代码;

我们将在一个switch代码中维护3种变化。将1的处理代码段,模块化为函数后,变化点减少为2个。

在分支增加到几十个时,代码维护性变得很差;而且switch对非整数类型无能为力。

二、表驱动法

做法:

1.  将变化点2,做成一个[关键字:处理函数]映射结构(推荐map容器),在独立函数中赋值。
2.  将变化点3,做成一个查找关键字,执行对应函数的简单函数

好处:

1.  独立出“选择分支”变化点,变为固定的处理流程。
2.  独立出“关键字和处理函数的关联”,易于维护。

限制条件:

1.  处理函数类型一样(这在C++中不成问题);
2.  处理函数简单,但每个函数有差异(如果处理较为复杂,请使用创建型设计模式)

扩展:

1.  对于处理函数由符合条件分支情况,变化点2使用list结构,按优先级关联处理函数,使用 “职责链”形式的表驱动法。

三、C++实现注意

代码:

// 3个文件,Client.cpp, TableDrave.h, TableDrive.cpp
 
// vvvvv Client.cpp begin
 
// ------------------------------------------------------------
// Name         :   Client.cpp
// Description  :   调用接口
// History      : 
// ------------------------------------------------------------
 
#include    "TableDrive.h"
 
// ------------------------------------------------------------
 
int main()
{
    TableDrive test;
    
    test.HandleKeyword(KEYWORD_A);
    test.HandleKeyword(KEYWORD_B);
    test.HandleKeyword(KEYWORD_C);
    test.HandleKeyword(KEYWORD_START);
    test.HandleKeyword(KEYWORD_D);
    
    return 0;
}
 
// ^^^^^ Client.cpp end
 
 
 
// vvvvv TableDrive.h begin
 
// ------------------------------------------------------------
// Name         :   TableDrive.h
// Description  :   表驱动头文件
// History      :   
// ------------------------------------------------------------
 
#ifndef     _TEST_DRIVE_H
#define     _TEST_DRIVE_H
 
 
#include    <map>
 
// ------------------------------------------------------------
 
// 测试用关键字
enum KEYWORD
{
    KEYWORD_START = -1,
    
    KEYWORD_A = 0,
    KEYWORD_B,
    KEYWORD_C,
    KEYWORD_D,  
    
    KEYWORD_END,
};
 
 
// ------------------------------------------------------------
 
// 可以使用 std:: 单个引用
using namespace std;
 
class TableDrive
{
public: 
 
    // ------------------------------------------------------------
    // Description : 
    //      根据关键字,执行处理函数
    // Parameters : 
    //      string keyword,关键字
    // Return Value : 
    //      bool,true,函数执行成功,false,找不到键字对应的函数,或函数执行失败
    // Errors : 
    //      无
    // ------------------------------------------------------------ 
    bool HandleKeyword(int keyword);
    
    // ------------------------------------------------------------
    // Description : 
    //      关联关键字到处理函数
    // Parameters : 
    //      无
    // Return Value : 
    //      bool,true,正常,false,异常
    // Errors : 
    //      无
    // ------------------------------------------------------------ 
    bool MapKeyToHandle();  
    
 
    TableDrive();
    
    ~TableDrive();
    
private:
    
    // vv 处理函数,true,执行成功,false,执行失败
    bool HandleKeyA();
    bool HandleKeyB();
    bool HandleKeyC();
    // ^^
    
private:
 
    // :TRICKY: 成员函数指针定义
    typedef bool (TableDrive:: *PHandle)(void);
    map<int, PHandle>   m_KeyToHandle;      // 关键字对应处理函数
};
 
#endif
 
// ^^^^^ TableDrive.h end
 
 
 
 
// vvvvv TableDrive.cpp begin
 
// ------------------------------------------------------------
// Name         :   TableDrive.cpp
// Description  :   表驱动实现文件
// History      : 
// ------------------------------------------------------------
 
#include    <stdio.h>
 
#include    "TableDrive.h"
 
// ------------------------------------------------------------
 
 
// 根据关键字,执行处理函数
bool TableDrive::HandleKeyword(int keyword)
{
    typedef map<int, PHandle>::const_iterator CI;
    CI iter = m_KeyToHandle.find(keyword);
 
    // 没有搜索到关键字
    if (m_KeyToHandle.end() == iter)
    {
        printf("\n  @@ search Keyword %d fail!\n", keyword);
        return false;
    }
 
    // :TRICKY: 注意成员函数指针的引用格式
    PHandle pFunction = iter->second;
    return (this->*pFunction)();
}
 
 
TableDrive::TableDrive()
{
    printf("\n  vv TableDrive::TableDrive()\n");
    MapKeyToHandle();
}
 
TableDrive::~TableDrive()
{
    printf("\n  ^^ TableDrive::~TableDrive()\n");
}
 
 
// ------------------------------------------------------------
 
// 关联关键字到处理函数
bool TableDrive::MapKeyToHandle()
{
    m_KeyToHandle[KEYWORD_A]    = &TableDrive::HandleKeyA;
    m_KeyToHandle[KEYWORD_B]    = &TableDrive::HandleKeyB;
    m_KeyToHandle[KEYWORD_C]    = &TableDrive::HandleKeyC;
        
    return true;
}
 
 
// 处理函数 A
bool TableDrive::HandleKeyA()
{
    printf("\n  ** A, HandleKeyA()\n\n");
    
    return true;
}
 
bool TableDrive::HandleKeyB()
{
    printf("\n  ** B, HandleKeyB()\n\n");
    
    return true;
}
 
bool TableDrive::HandleKeyC()
{
    printf("\n  ** C, HandleKeyC()\n\n");
    
    return true;
}
 
// ^^^^^ TableDrive.cpp end

关注点:

主要关注3个点,维护第2、3点

1.   HandleKeyword(),根据关键字,执行处理函数。固定后基本不改变;
2.   MapKeyToHandle(),关联关键字到处理函数;
3.   Handle(),各个处理函数

成员函数指针使用注意

1.  声明格式,与C相比,函数指针前要包含类域;
typedef bool (TableDrive:: *PHandle)();

2.  声明位置,包含在类中,否则不能识别类域标志;

3.  赋值语法格式,与C相比,函数指针前要包含类域;
PHandle pFunction = &TableDrive::HandleKeyA;

4.  调用语法格式,与C相比,需要加上this,并以强制解引用方式调用;
(this->*pFunction)();

 四、实用案例

1.  菜单调节。一个模块,有几十个菜单参数可以调节,每个菜单调节的步进、范围不同,但都是“触发消息、调节数值”流程。

2.  按键响应。多个按键,属于“按键,执行对应处理函数”流程。

3.  鼠标操控。不同状态下移动鼠标,属于“状态判断、响应鼠标处理函数”流程。

 表驱动法

上一篇:C语言中判断素数(求素数)的思路与方法实例

栏    目:C代码

下一篇:C语言详尽图解函数栈帧的创建和销毁实现

本文标题:如何用c++表驱动替换if/else和switch/case语句

本文地址:http://www.codeinn.net/misctech/226153.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有