首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >状态机变更状态

状态机变更状态
EN

Stack Overflow用户
提问于 2020-10-27 21:30:05
回答 2查看 667关注 0票数 1

我不断地遇到同样的问题,即使在阅读教程时也无法修复它。我已经“设置”了我的国家机器,但我不能在各州之间过渡。

这是我的StateMachine:

代码语言:javascript
复制
class StateMachine
{
    State* m_State;

public:
    StateMachine();
    ~StateMachine();
    void changeState(State* state);
};

下面是一个例子:

代码语言:javascript
复制
class A : State
{
public:
    A();
    ~A();
    void handleInput(int a);
}

如果我将a=1传递给A::handleInput(),我希望转换到状态B。但是当我实现它时,我无法从A::handleInput()访问StateMachine,这使我痛苦地擦洗了头。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-27 21:53:27

,但是当我实现它时,我无法从A::handleInput()访问StateMachine

嗯,这是中一个众所周知的问题,没有提到如何使用一个封闭的状态机来跟踪状态类。

IMO,这是将StateMachine类作为实现的有效用例之一。

这样,它的实例就可以从任何State类实现中访问。

正如我在这里所说的设计模式,状态类可以在的帮助下设计,因为它们本身通常是无状态的。

我曾经将所有这些都转化为一个c++模板框架,该框架抽象了状态机和状态机的接口(参见下面的链接)。

下面是一个简短的代码示例:

StateMachine.h

代码语言:javascript
复制
struct State {
    virtual void handleInput(int x) = 0;
    virtual ~State() {} = 0;
};

class StateMachine {
    State* m_State;

    StateMachine();
public:
   
    static StateMachine& instance() {
        static StateMachine theInstance;
        return theInstance;
    }
    void changeState(State* state) {
        m_State = state;
    }
    void triggerInput(int x) {
        m_State->handleInput(x);
    }
};

StateA.h

代码语言:javascript
复制
#include "StateMachine.h"
class StateB;
extern StateB* stateB;

class StateA : public State {
public:
    virtual ~StateA() {}
    virtual void handleInput(int x) {
        if(x == 1) {
             // Change to StateB
             StateMachine::instance.changeState(stateB);
        }
        else {
            // Do something with x
        }
    }
};

我在这里省略了StateB的定义,应该和StateA一样。

参考文献:

票数 0
EN

Stack Overflow用户

发布于 2020-10-27 23:04:25

我看了一下源代码生成示例,对我来说,实现示例非常糟糕;必须在每个状态更改上创建新实例:https://sourcemaking.com/design_patterns/state/cpp/1

作为一个用JK触发器在电子领域设计状态机的人,我会使用一种类似但语义不同的方法。状态机中的复杂性涉及到根据状态和输入执行的操作;通常,在C语言中,可以使用大量的开关语句,可能还有描述如何处理current statenew input ( event )的数组。

所以对我来说,面向对象的方法就是对event handler建模。这将有一个接口来描述输入的格式。然后,对于每个不同的状态,您就有了不同的接口实现。这样,状态机就可以简单地将状态集合实现到事件处理程序--数组、向量或映射。虽然处理程序仍然可能包含case语句,但总体的混乱程度大大减少了。您可以在必要时使用新的状态处理程序轻松地扩展设计:

所以你可以有这样的东西:

代码语言:javascript
复制
#include <map>

typedef enum
{
    //TODO : state list, e.g.
    eOff,
    eOn
}
teCurrentState;

typedef struct
{
    //TODO : Add inputs here, e.g.
    bool switch1;
}
tsInputDesc;

typedef struct
{
    //TODO : Add outputs here, e.g.
    bool relay1;
}
tsOutputDesc;

// ------------------------------------------------

class IEventHandler
{
public:
    virtual ~IEventHandler() {}
    // returns new state
    virtual teCurrentState handleInput(tsInputDesc const& input, tsOutputDesc& output) = 0;
};

// ------------------------------------------------

class OnStateHandler : public IEventHandler
{
public:
    virtual teCurrentState handleInput(tsInputDesc const& input, tsOutputDesc& output) override
    {
        //TODO : IMPLEMENT
        teCurrentState newState = TODO....
        return (newState);
    }
};

// ------------------------------------------------

class OffStateHandler : public IEventHandler
{
public:
    virtual teCurrentState handleInput(tsInputDesc const& input, tsOutputDesc& output) override
    {
        //TODO : IMPLEMENT
        teCurrentState newState = TODO....
        return (newState);
    }
};

// ------------------------------------------------

class StateMachine
{
protected:
    teCurrentState mCurrentState;
    std::map<teCurrentState, IEventHandler*> mStateHandlers;

    void makeHandlers()
    {
        mStateHandlers[eOff] = new OffStateHandler();
        mStateHandlers[eOn] = new OnStateHandler();
    }

public:
    StateMachine()
    {
        makeHandlers();
        mCurrentState = eOff;
    }

    void handleInput(tsInputDesc const& input, tsOutputDesc output)
    {
        teCurrentState newState = mStateHandlers[mCurrentState]->handleInput(input, output);
        mCurrentState = newState;
    }
};

// ------------------------------------------------

void runFsm()
{
    StateMachine fsm;
    tsInputDesc input;
    tsOutputDesc output;
    bool alive = true;

    while (alive)
    {
        // TODO : set input according to....inputs (e.g. read I/O port etc)

        fsm.handleInput(input, output);

        // TODO : use output
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64563173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档