我正在试验状态机,而我正在尝试实现的那个使用函数指针来表示状态
typedef void (*State)(Signal const&)
class StateMachine
{
public:
void exampleState(Signal const&);
private:
State m_currentState;
}
基本上,我想为每个信号派生一个单独的类,并且在每个状态函数中,状态机必须能够确定已经接收了哪种信号并执行相应的代码。我提出的解决方案是类似的
class Signal {};
class MySignal: public Signal {};
void StateMachine::exampleState(Signal const& signal){
if (typeid(signal) == typeid(MySignal)){
//code here
}
// other cases...
}
首先,我不确定以这种方式使用typeid是一种很好的做法。此外,这仅在Signal具有至少一个虚拟功能时才有效。
另一种解决方案是定义一种类型的标志,如枚举,并在派生信号构造函数中传递相应的一个
enum signalType{
mySignalType
//other types
}
class Signal {
public:
Signal(signalType sig_type):m_type(sig_type){};
const signalType m_type;
};
class MySignal: public Signal {
public:
MySignal():Signal(mySignalType){};
};
void StateMachine::exampleState(Signal const& signal){
switch (signal.m_type){
case mySignalType:
//code here
break;
// other cases...
}
}
虽然这要求每次写入新的信号类时都要扩展枚举。
有更优雅的方式实现这一目标吗?或者也许是另一种可以避免这种检查的技术?我记得在其他场景中也有这个问题,这就是为什么标题中的问题比上面的例子更普遍。
使用dynamic_cast
而不是typeid
:
class Signal {
public:
virtual ~Signal() {}
};
class MySignal: public Signal {};
void StateMachine::exampleState(Signal const& signal){
if (dynamic_cast<MySignal const *>(&signal)){
//code here
}
// other cases...
}
你想要实现的目标可以通过多态实现。
在Signal
中声明一个方法(或抽象方法),并在MySignal
中实现它:
class Signal {
public:
virtual void my_method() const = 0;
};
class MySignal: public Signal {
public:
void my_method() const override {
// do something
}
};
然后在exampleState
中调用你的方法,这将调用实现的方法:
void StateMachine::exampleState(Signal const& signal){
signal.my_method();
}