状态机(Finite State Machine, FSM)是一种数学模型,用于表示有限个状态以及在这些状态之间的转移和动作。在C/C++中,实现状态机有多种方法,下面介绍几种常见的实现方式。
1. 使用switch-case语句
这是最简单直接的方法。可以通过一个状态变量来记录当前状态,然后在循环或事件驱动中使用switch-case根据当前状态执行相应的操作,并根据事件或条件进行状态转移。
cpp
#include <iostream>
enum State {
STATE_A,
STATE_B,
STATE_C
};
State currentState = STATE_A;
void runStateMachine(int event) {
switch (currentState) {
case STATE_A:
if (event == 1) {
std::cout << "State A: Processing event 1, moving to State B" << std::endl;
currentState = STATE_B;
} else {
std::cout << "State A: Unknown event" << std::endl;
}
break;
case STATE_B:
if (event == 2) {
std::cout << "State B: Processing event 2, moving to State C" << std::endl;
currentState = STATE_C;
} else if (event == 3) {
std::cout << "State B: Processing event 3, moving to State A" << std::endl;
currentState = STATE_A;
} else {
std::cout << "State B: Unknown event" << std::endl;
}
break;
case STATE_C:
std::cout << "State C: Final state, no transitions" << std::endl;
break;
}
}
int main() {
int events[] = {1, 2, 3, 1, 2};
for (int event : events) {
runStateMachine(event);
}
return 0;
}
2. 使用函数指针
将每个状态实现为一个函数,函数返回下一个状态。然后使用一个函数指针来维护当前状态函数,每次调用状态函数并更新函数指针。
cpp
#include <iostream>
// 状态函数类型定义
typedef void (*StateFunction)(int);
// 前向声明状态函数
void stateA(int event);
void stateB(int event);
void stateC(int event);
// 全局状态变量
StateFunction currentState = stateA;
void stateA(int event) {
if (event == 1) {
std::cout << "State A: Processing event 1, moving to State B" << std::endl;
currentState = stateB;
} else {
std::cout << "State A: Unknown event" << std::endl;
}
}
void stateB(int event) {
if (event == 2) {
std::cout << "State B: Processing event 2, moving to State C" << std::endl;
currentState = stateC;
} else if (event == 3) {
std::cout << "State B: Processing event 3, moving to State A" << std::endl;
currentState = stateA;
} else {
std::cout << "State B: Unknown event" << std::endl;
}
}
void stateC(int event) {
std::cout << "State C: Final state, no transitions" << std::endl;
}
void runStateMachine(int event) {
currentState(event);
}
int main() {
int events[] = {1, 2, 3, 1, 2};
for (int event : events) {
runStateMachine(event);
}
return 0;
}
3. 使用状态模式(面向对象)
在C++中,可以使用面向对象的方式,将每个状态封装为一个类,并有一个共同的基类。状态机类维护一个指向当前状态对象的指针,通过多态调用当前状态的处理函数。
cpp
#include <iostream>
// 前向声明
class State;
// 状态机上下文类
class StateMachine {
public:
StateMachine();
void setCurrentState(State* state);
void handleEvent(int event);
private:
State* currentState;
};
// 抽象状态基类
class State {
public:
virtual void handle(StateMachine& context, int event) = 0;
virtual ~State() {}
};
// 具体状态类
class StateA : public State {
public:
void handle(StateMachine& context, int event) override;
};
class StateB : public State {
public:
void handle(StateMachine& context, int event) override;
};
class StateC : public State {
public:
void handle(StateMachine& context, int event) override;
};
// 状态机成员函数定义
StateMachine::StateMachine() {
currentState = new StateA();
}
void StateMachine::setCurrentState(State* state) {
delete currentState;
currentState = state;
}
void StateMachine::handleEvent(int event) {
currentState->handle(*this, event);
}
// 具体状态处理函数
void StateA::handle(StateMachine& context, int event) {
if (event == 1) {
std::cout << "State A: Processing event 1, moving to State B" << std::endl;
context.setCurrentState(new StateB());
} else {
std::cout << "State A: Unknown event" << std::endl;
}
}
void StateB::handle(StateMachine& context, int event) {
if (event == 2) {
std::cout << "State B: Processing event 2, moving to State C" << std::endl;
context.setCurrentState(new StateC());
} else if (event == 3) {
std::cout << "State B: Processing event 3, moving to State A" << std::endl;
context.setCurrentState(new StateA());
} else {
std::cout << "State B: Unknown event" << std::endl;
}
}
void StateC::handle(StateMachine& context, int event) {
std::cout << "State C: Final state, no transitions" << std::endl;
}
int main() {
StateMachine sm;
int events[] = {1, 2, 3, 1, 2};
for (int event : events) {
sm.handleEvent(event);
}
return 0;
}
4. 使用状态表(适合复杂状态机)
通过预定义的状态转移表和动作表,将状态和事件作为键,映射到下一个状态和对应的处理动作。当事件发生时,根据当前状态和事件查找表,执行相应的动作并转移到新状态,实现状态机的集中管理和灵活配置。
cpp
#include <iostream>
#include <map>
#include <functional>
// 状态和事件类型
enum class State { IDLE, RUNNING, PAUSED, STOPPED };
enum class Event { START, PAUSE, RESUME, STOP };
class StateMachine {
private:
State currentState;
// 状态转移表:当前状态 + 事件 -> 新状态
std::map<std::pair<State, Event>, State> transitionTable;
// 状态转移动作
std::map<std::pair<State, Event>, std::function<void()>> actionTable;
public:
StateMachine() : currentState(State::IDLE) {
// 初始化状态转移表
transitionTable = {
{{State::IDLE, Event::START}, State::RUNNING},
{{State::RUNNING, Event::PAUSE}, State::PAUSED},
{{State::RUNNING, Event::STOP}, State::STOPPED},
{{State::PAUSED, Event::RESUME}, State::RUNNING},
{{State::PAUSED, Event::STOP}, State::STOPPED},
{{State::STOPPED, Event::START}, State::RUNNING}
};
// 初始化动作表
actionTable = {
{{State::IDLE, Event::START}, [this]() {
std::cout << "从空闲状态启动" << std::endl;
}},
{{State::RUNNING, Event::PAUSE}, [this]() {
std::cout << "暂停运行" << std::endl;
}},
{{State::RUNNING, Event::STOP}, [this]() {
std::cout << "停止运行" << std::endl;
}},
{{State::PAUSED, Event::RESUME}, [this]() {
std::cout << "恢复运行" << std::endl;
}},
{{State::PAUSED, Event::STOP}, [this]() {
std::cout << "从暂停状态停止" << std::endl;
}},
{{State::STOPPED, Event::START}, [this]() {
std::cout << "重新启动" << std::endl;
}}
};
}
void handleEvent(Event event) {
auto key = std::make_pair(currentState, event);
if(transitionTable.find(key) != transitionTable.end()) {
// 执行状态转移动作
if(actionTable.find(key) != actionTable.end()) {
actionTable[key]();
}
// 更新状态
currentState = transitionTable[key];
} else {
std::cout << "无效的状态转移: " << static_cast<int>(currentState)
<< " -> " << static_cast<int>(event) << std::endl;
}
}
State getCurrentState() const {
return currentState;
}
};
int main() {
StateMachine sm;
// 模拟一系列事件
Event events[] = {
Event::START, Event::PAUSE, Event::RESUME,
Event::PAUSE, Event::STOP, Event::START
};
for(auto event : events) {
std::cout << "当前状态: " << static_cast<int>(sm.getCurrentState())
<< ", 处理事件: " << static_cast<int>(event) << std::endl;
sm.handleEvent(event);
}
return 0;
}
5. 总结
- Switch-case方法:简单直接,适合状态数量少且转换逻辑简单的场景,扩展性差。
- 函数指针方法:更灵活,比switch-case更模块化,状态逻辑各自独立,但全局变量可能带来问题(可使用上下文结构体避免),适合中等复杂度的状态机。
- 状态模式:面向对象的方式,符合开闭原则,易于扩展,但代码量相对较大,适合复杂的状态机。
- 状态表方法:使用表驱动,将状态转移逻辑数据化,适合非常复杂的状态机。