状态机在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. Selenium WebDriver高级用法

    Selenium GitHub地址 选择合适的WebDrvier WebDriver是一个接口,它有几种实现,分别是HtmlUnitDrvier.FirefoxDriver.InternetExplo ...

  2. 如何解决 错误code signing is required for product type 'xxxxx' in SDK 'iOS 8.2'

    如何解决 错误code signing is required for product type 'xxxxx' in SDK 'iOS 8.2' 大家在做真机调试的时候,或许会遇到这样的问题,那如何 ...

  3. Luogu【P2904】跨河(DP)

    题目链接在这里 此题DP.用一个前缀和一样的东西,把载i个奶牛的时间求出来,然后DP代码如下: ;i<=n;++i){ f[i]=que[i]; ;j<i;++j) f[i]=min(f[ ...

  4. 3931: [CQOI2015]网络吞吐量【网络流】

    网络吞吐量(network)题目描述路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最快的到达目的地,路 ...

  5. N*N数码问题

    奇数码问题 时间限制: 1 Sec  内存限制: 128 MB 题目描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中. ...

  6. springboot收集

    Spring Boot实战:拦截器与过滤器 参考:https://blog.csdn.net/m0_37106742/article/details/64438892 https://www.ibm. ...

  7. Linux java 启动脚本

    #!/bin/bash export LANG=en_US.UTF8 start(){ ulimit -n 65535 #find the jars jar_lib=`ls -1 lib/*.jar` ...

  8. maven编码gbk的不可映射字符

    如图,老是出现这个错误,百度说是打开源文件,更改编码格式,或者是更改File Encodings 的编码格式,或者是更改java compiler --use computer为eclipse, 都不 ...

  9. hdu - 1269 迷宫城堡 (强连通裸题)

    http://acm.hdu.edu.cn/showproblem.php?pid=1269 判断一个图是不是强连通,缩点之后判断顶点数是不是为1即可. #include <iostream&g ...

  10. Android判断屏幕锁屏的方法总结

    由于做一个项目,需要判断屏幕是否锁屏,发现网上方法很多,但是比较杂,现在进行总结一下: 总共有两类方法: 一.代码直接判定 二.接收广播 现在先说第一类方法(代码直接判定): 1.通过PowerMan ...