状态机在project中使用很的频繁,有例如以下常见的三种实现方法:

1. switch-case 实现。适合简单的状态机。

2. 二维状态表state-event实现。逻辑清晰。可是矩阵通常比較稀疏,并且维护麻烦。

3. 用状态转移表stateTransfer Table实现,数组大小等于状体转移边个数,易扩展;

以下用一个样例来进行具体说明,描写叙述的例如以下场景:

描写叙述对象:门

状态:开着、关着、锁着 (这里的关着指关了但未锁的状态)

事件:开门、关门、上锁、解锁

代码实现用枚举来定义状态和事件,操作数据节点转移到目的状态用函数实现。枚举本身默认是从0開始的int类型,利用这个特点将状态转移函数放到函数指针数组中与状态相应起来。方便操作。

核心数据结构例如以下:

状态:枚举类型

事件:枚举类型

状态转移结构体:{当前状态、事件、下个状态},定义一个全局数组来使用

状态变更函数:到下个状态(放到数组中与状态枚举相应起来)

此种实现方法easy扩展,添加状态和事件都比較easy。

假设存在一个状态通过相应事件能够转移到多个状态的情形,则能够扩展状态转移函数。或者在状态转移结构中添加一个推断函数字段。

代码实现例如以下:

#include <iostream>
using namespace std; typedef enum{
OPENED,
CLOSED,
LOCKED,
} State; typedef enum{
OPEN,
CLOSE,
LOCK,
UNLOCK
} Event; typedef struct{
State currentState;
Event event;
State NextState;
} StateTransfer; typedef struct{
State state;
int transferTimes;
}Door; StateTransfer g_stateTransferTable[]{
{OPENED, CLOSE, CLOSED},
{CLOSED, OPEN, OPENED},
{CLOSED, LOCK, LOCKED},
{LOCKED, UNLOCK, CLOSED},
}; void toOpen(Door& door);
void toClose(Door& door);
void toLock(Door& door);
typedef void (*pfToState)(Door& door);
pfToState g_pFun[] = {toOpen, toClose, toLock}; //状态枚举值相应下标 void toOpen(Door& door){
door.state = OPENED;
cout << "open the door!\n";
} void toClose(Door& door){
door.state = CLOSED;
cout << "close the door!\n";
} void toLock(Door& door){
door.state = LOCKED;
cout << "lock the door!\n";
} void transfer(Door& door,const Event event){
for (int i = 0; i < sizeof(g_stateTransferTable)/sizeof(StateTransfer); ++i) {
if(door.state == g_stateTransferTable[i].currentState &&
event == g_stateTransferTable[i].event){
g_pFun[g_stateTransferTable[i].NextState](door);
door.transferTimes++;
cout << "transfer ok!\n";
return;
}
}
cout << "This event cannot transfer current state!!\n";
return;
} void printDoor(const Door& door){
string stateNote[] = {"opened","closed","locked"}; // 下标正好相应状态枚举值
cout << "the door's state is: " << stateNote[door.state] << endl;
cout << "the door transfer times is: " << door.transferTimes << endl;
} int main(){
Door door = {CLOSED, 0};
printDoor(door);
transfer(door, OPEN);
printDoor(door);
transfer(door, LOCK);
printDoor(door);
transfer(door, CLOSE);
printDoor(door);
return 0;
}

执行结果例如以下:

the door’s state is: closed

the door transfer times is: 0

open the door!

transfer ok!

the door’s state is: opened

the door transfer times is: 1

This event cannot transfer current state!!

the door’s state is: opened

the door transfer times is: 1

close the door!

transfer ok!

the door’s state is: closed

the door transfer times is: 2

C/C++用状态转移表联合函数指针数组实现状态机FSM的更多相关文章

  1. C 函数指针 函数指针数组 转移表

    内容来自<c和指针>,整理后方便个人理解 高级声明 cdel程序可以方便的给出声明的释义 指向函数的指针 int ( *f ) ( int n_values, float amount ) ...

  2. c语言.函数指针数组

    函数指针: 一个指向函数的指针.一般用函数名表示. 函数指针数组:元素为函数指针的数组.转移表.c语言中函数不可以定义为数组,只能通过定义函数指针来操作. #include<stdio.h> ...

  3. 转:函数指针数组的妙用(I)

    转自:http://blog.sina.com.cn/s/blog_4c78b35f010008hi.html 笔者在开发某软件过程中遇到这样一个问题,前级模块传给我二进制数据,输入参数为 char* ...

  4. C++基础——函数指针 函数指针数组

    ==================================声明================================== 本文版权归作者所有. 本文原创,转载必须在正文中显要地注明 ...

  5. typedef 函数指针 数组 std::function

    1.整型指针 typedef int* PINT;或typedef int *PINT; 2.结构体 typedef struct { double data;}DATA,  *PDATA;  //D ...

  6. C#委托与C语言函数指针及函数指针数组

    C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用 ...

  7. C/C++ 一段代码区分数组指针|指针数组|函数指针|函数指针数组

    #include<stdio.h> #include<stdlib.h> #include<windows.h> /* 举列子说明什么是函数指针 */ //以一个加 ...

  8. C/C++ 不带参数的回调函数 与 带参数的回调函数 函数指针数组 例子

    先来不带参数的回调函数例子 #include <iostream> #include <windows.h> void printFunc() { std::cout<& ...

  9. C 函数指针数组

    名字有点绕口,其实更应该翻译为指针函数数组. 记录下对Head-First C这一节的理解,几乎每天班车上都会咪两眼,几乎每次都是看不懂,敲一敲的时候才有些明白. 通俗点讲,这功能解决的是,具有同种签 ...

随机推荐

  1. 【LeetCode】Maximize Sum Of Array After K Negations(K 次取反后最大化的数组和)

    这道题是LeetCode里的第1005道题. 题目描述: 给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次. ...

  2. linux下连接到远程主机,用图像界面(想在远程服务器上用cmake)

    1. 需要通过SSH -X username@ip登陆服务器后,再用图形界面,比如用cmake 2.直接用 SSH username@ip命令登陆服务器后,不能用cmake

  3. nginx的详解(四)

    10.nginx的访问控制及DDOS预防1)访问控制配置基于各种原因,Ningx有时要进行访问控制.比如说,一般网站的后台都不能让外部访问,所以要添加 IP 限制,通常只允许公司的IP访问.访问控制就 ...

  4. hdu6073[dfs+删边] 2017多校4

    题目中对二分图的定义十分特殊, 指的是 U,V两部分中,U的顶点度数必定为2,V中顶点无限制. 题目要求的是 对于所有匹配,该匹配的权值=该匹配中选中的边的边权的乘积,求所有匹配权值之和. 对于V中的 ...

  5. bzoj1064【Noi2008】假面舞会

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1064 给一个有向图染色,每个点的后继必须相同,问至少&至多有多少种染色方案 sol: ...

  6. Snmp的学习总结(二)

    一.SNMP简介 SNMP指的是简单网络管理协议.它属于TCP/IP五层协议中的应用层协议.它提供了一种简单和方便的模式来管理网络中的各个元素.这里的元素就是各个被管理的对象,可以是因特网中的某个硬件 ...

  7. hdu3038 How Many Answers Are Wrong

    TT and FF are ... friends. Uh... very very good friends -________-b FF is a bad boy, he is always wo ...

  8. ndarray:一种多维数组对象

    ndarray是一个通用的同构数据多维容器,也就是说,其中的所有元素必须是相同类型的.每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组数据类型的对象). In ...

  9. 【HDOJ6228】Tree(树)

    题意:有一棵n个点的树,在树上的点涂色,每个点涂一种颜色,一共可以涂k种颜色, 然后把同一种颜色(比如说x)的点用最优方案连起来,在连线的边涂上x颜色,问涂k次的边最多有几条 k<=500 si ...

  10. Python入门--2--继续学习

    继续学习小甲鱼 一.python比较操作符 == :判断左边是否等于右边 != : 判断左边是否不能右边 二. if while判断语句 栗子: temp = input ("sha shu ...