【C/C++】C/C++状态机实现方法

状态机(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更模块化,状态逻辑各自独立,但全局变量可能带来问题(可使用上下文结构体避免),适合中等复杂度的状态机。
  • 状态模式:面向对象的方式,符合开闭原则,易于扩展,但代码量相对较大,适合复杂的状态机。
  • 状态表方法:使用表驱动,将状态转移逻辑数据化,适合非常复杂的状态机。
相关推荐
轩情吖3 小时前
Qt常用控件之QLabel(一)
开发语言·数据库·c++·qt·小程序·qlabel·桌面开发
m0_552200823 小时前
《UE5_C++多人TPS完整教程》学习笔记58 ——《P58 旋转奔跑动画(Rotate Running Animations)》
c++·游戏·ue5
青草地溪水旁5 小时前
设计模式(C++)详解—享元模式(1)
c++·设计模式·享元模式
雪域迷影5 小时前
使用C++编写的一款射击五彩敌人的游戏
开发语言·c++·游戏
郝学胜-神的一滴5 小时前
享元模式(Flyweight Pattern)
开发语言·前端·c++·设计模式·软件工程·享元模式
charlie1145141916 小时前
精读《C++20设计模式》——创造型设计模式:构建器系列
c++·设计模式·c++20·构造器模式
小莞尔6 小时前
【51单片机】【protues仿真】基于51单片机恒温箱系统
c语言·开发语言·单片机·嵌入式硬件·51单片机
小王努力学编程6 小时前
brpc远程过程调用
linux·服务器·c++·分布式·rpc·protobuf·brpc
青草地溪水旁7 小时前
设计模式(C++)详解—享元模式(2)
c++·设计模式·享元模式