gpt4 book ai didi

c++ - 如何强制耦合多态类型和枚举值?

转载 作者:太空宇宙 更新时间:2023-11-04 12:09:42 25 4
gpt4 key购买 nike

我有一个状态机,它有一个状态,它向外部接收器发送一些消息(例如文本)。在转换到此状态(我们称之为 Dispatching)之前,先前的状态需要在某处存储该消息,以便 Dispatching 稍后可以获取它。当消息在一个上下文中创建并在另一个上下文中使用时,它将在堆上创建,并且 State Manager 对象(管理状态、转换和事件循环)保留指向它的引用/指针。状态对象在状态机通过状态时创建和销毁。每个状态继承抽象基类State:

enum StateID
{
STATE_A,
STATE_B,
...
};

class State
{
public:
State(StateID stateID, StateManager& sm) :
stateID_(stateID), sm(sm_){}
virtual ~State(){};
virtual StateID HandleEvent(const Event& e) = 0;
StateID id() const {return stateID_;}
protected:
StateID stateID_;
StateManager& sm_;
};

为了将数据传递到下一个状态,我想出了 StateData 的想法 - 从一个状态传递到下一个状态的一条信息。它存储在动态内存中,状态管理器保留对它的引用,以便每个状态都可以访问它。由于不同类型的数据可能会传递给不同的状态,因此可以将 StateData 设为抽象基类,专门用于每个特定状态:

struct StateData
{
virtual ~StateData() = 0;
};

struct StateAData : public StateData
{
int n_;
StateAData(int n) : n_(n){}
};

struct StateBData : public StateData
{
std::string str_;
StateBData(const std::string& str) : str_(str){}
};

...

class StateManager
{
boost::scoped_ptr<State> pCurrState_;
boost::scoped_ptr<StateData> pStateData_;
...
public:
void runEventLoop()
{
while(true)
{
...
//get event from a queue
...

StateID nextStateID = pCurrState_->HandleEvent(e);

if(nextStateID == pCurrState_->id())
continue;

pCurrState_.reset(0);

switch(nextStateID)
{
case STATE_A:
pCurrState_.reset(new StateA(*this));
break;
case STATE_B:
pCurrState_.reset(new StateB(*this));
break;
case STATE_C:
pCurrState_.reset(new StateC(*this));
break;
...
}
}
}
...
};

class StateA
{
public:
StateA(StateManager& sm) : State(STATE_A, sm){}

StateID HandleEvent(const Event& e)
{
switch(e.ID)
{
case EVENT_1:
{
StateAData* pData = reinterpret_cast<StateAData*>(stateMachine_.pStateData_.get());
// do something with data, e.g. use it for transition logic
if(pData->n_ % 2)
{
stateMachine_.pStateData_.reset(new StateBData("Hello from StateA"));
return STATE_B;
}
else
{
...
}
break;
}
...
}
}
...
}

下面几行有一个陷阱:

stateMachine_.pStateData_.reset(new StateBData("Hello from StateA"));
return STATE_B;

如果转换逻辑发生变化,那么我们需要从这里转到 STATE_C,开发人员可能会忘记将 StateBData 的类型更改为 StateCData:

stateMachine_.pStateData_.reset(new StateBData("Hello from StateA"));
return STATE_C;

...当 StateC 尝试将 StateData 转换为 StateCData 时,这会导致意外行为。

如何避免这种情况?如何强制匹配创建对象的类型和返回的枚举值?

是的,这段代码很糟糕,这是使用两段信息和使用 enum 来区分状态类型而不是类型本身的结果。 HandleEvent 可以返回 StateXData 并根据此返回类型(因为它携带有关下一个状态的信息)状态管理器将确定(通过使用 RTTI)要转换到的下一个状态(X) 但我不喜欢这个解决方案。

另一个想法是创建下一个状态的实例并将其数据传递到其构造函数,但这种方法会污染状态机设计,因为一个状态将在前一个状态被销毁之前创建。

最佳答案

使 enum 成为基类的一部分,或者在基类中提供一个纯 virtual 函数来返回这个 enum。这样,状态本身将公布其类型。

关于c++ - 如何强制耦合多态类型和枚举值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10350866/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com