Search code examples
c++polymorphism

C++ - Identify derived class from base class pointer at runtime


I'm experimenting with state machines and the one that I'm trying to implement uses function pointers to represent states

typedef void (*State)(Signal const&)

class StateMachine
{
public:
    void exampleState(Signal const&);
private:
    State m_currentState;
}

Basically, I want to derive a separate class for each signal and in each state function the state machine must be able to determine which kind of signal has been received and execute the corresponding code. A solution that I came up with is something like

class Signal {};
class MySignal: public Signal {};

void StateMachine::exampleState(Signal const& signal){
    if (typeid(signal) == typeid(MySignal)){
        //code here
    }
    // other cases...
}

First of all I'm not sure that using typeid this way is good practice. Also, this only works if Signal has at least one virtual function.

Another solution would be to define a sort of type flag like an enum, and pass the corresponding one in the derived signal constructor

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...
  }
}

althoug this requires the enum to be extended each time a new signal class is written.

Is there a more elegant way of achieving this? Or maybe another technique that avoids this check at all? I remember having this problem in other scenarios as well, that's why the question in the title is more general than the example above.


Solution

  • Use dynamic_cast instead of 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...
    }