0

I need some help with inheritance and coding to interfaces in C++. I'm creating a state machine from which I'll derive another state machine. Therefore I have two interacting parts, a StateMachine and a State. The problem is that with this design, I cannot derive a specialised State from either the StateMachine or a DerivedStateMachine.

class StateMachine; //fwd

class State {
public:
    virtual void action(StateMachine *engine) = 0;

    virtual ~State() = default;
};

class StateMachine {
public:
    StateMachine() = default;

    explicit StateMachine(State &state) : state_(&state) {};

    virtual void setState(State &state) {
        state_ = &state;
    }

    [[nodiscard]] virtual State *getState() const {
        return state_;
    }

protected:
    State *state_ = nullptr;

};
class DerivedStateMachine : public StateMachine {
public:
    using StateMachine::StateMachine;

    int doSpecializedThings(){
        return special_thing_;
    }

    void setSpecialState(int specialState) {
        special_thing_ = specialState;
    }

private:
    int special_thing_;
};

The issue with DerivedStateDependsOnGeneralStateMachine is that a StateMachine* doesn't have access to the doSpecializedThings() method.

class DerivedStateDependsOnGeneralStateMachine : public State {

    virtual void action(StateMachine *engine) {
        int important_value = engine->doSpecializedThings();
    };

};

And the problem with DerivedStateDependsOnDerivedStateMachine is that you can't override a method with different arguments to the parent.

class DerivedStateDependsOnDerivedStateMachine : public State {

    void action(DerivedStateMachine *engine) override {
        engine->doSpecializedThings();
    };

};

Can anybody see a way out of this knot I've tied myself in? Clearly I've messed up the design somewhere. What's 'normal' (for want of a better word) in such situations?

edits

To address the comments, firstly @Ted Lyngmo I am using the state machine design that I found in this post. It is odd that the mutual dependency is built into the design but its deliberate. The StateMachine needs to hold a reference to a State at all times and the State is responsible for determining the next state. The next state might depend on variables stored in the StateMachine so its useful to have a reference to the StateMachine in the State.

To get a little more concrete, I'm writing a Poker game. The idea is to have an abstract StateMachine interface from which I can derive a PokerEngine state machine, which conforms to the interface. I also thought I should have an abstract State, from which I can derive a PokerState. This would all work without the abstract level, and might initially be easier to think about, but its important for me to practice coding to interfaces to enable dependency injection and mocking. The irony is that in trying to do these things I've violated the Liskov substitution principle. Anyway, the PokerEngine will need to do things like getPotAmount which is a specialized method that I wouldn't want to any StateMachine.

CiaranWelsh
  • 7,014
  • 10
  • 53
  • 106
  • 2
    "_I'm creating a state machine from which I'll derive another state machine. Therefore I have two interacting parts, a StateMachine and a State._" - I don't see how inheriting a state machine results in a state machine and a state. Please elaborate on that part. – Ted Lyngmo Jan 15 '21 at 23:45
  • 1
    Someone might be able to help but for me the question is too abstract. I'd need an example to understand the situation. I like how you name things so it's easy to undersand and with names like `DerivedStateDependsOnDerivedStateMachine` I can't help feeling that something has derailed. - but, I'll leave it at that without seeing an example. It may make perfect sense. – Ted Lyngmo Jan 16 '21 at 00:09
  • Your design runs afoul of [the Liskov Substitution Principle](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle). This almost always makes life more difficult. See if you can make the `doSpecializedThings`-type functions `private` and call them from more-general `virtual` functions. In this case, perhaps `StateMachine ` has a virtual `doSpecializedThings` function that does nothing, but is called as part of the usual chain of events so derived classes can provide implementations to do those specialized things. – user4581301 Jan 16 '21 at 00:54
  • Thanks for the comments guys, I've edited my question to try to address your points. – CiaranWelsh Jan 16 '21 at 13:03

2 Answers2

0

I don't fully understand your design, but you can do what you need like this:

class StateMachine; //fwd

class State {
public:
    virtual void action(StateMachine *engine) = 0;

    virtual ~State() = default;
};

class StateMachine {
public:
    StateMachine() = default;

    explicit StateMachine(State &state) : state_(&state) {};

    virtual void setState(State &state) {
        state_ = &state;
    }
    virtual void setState(int state) {};

    [[nodiscard]] virtual State *getState() const {
        return state_;
    }

    virtual int doSpecializedThings(){
        std::cout << "Do StateMachine things (or nothing)" << std::endl;
        return 0;
    }
    
protected:
    State *state_ = nullptr;

};

class DerivedStateDependsOnGeneralStateMachine : public State {
public:

    virtual void action(StateMachine *engine) {
        int important_value = engine->doSpecializedThings();
    };

};

class DerivedStateDependsOnDerivedStateMachine : public State {
public:
    void action(StateMachine *engine) override {
        engine->doSpecializedThings();
    };

};

class DerivedStateMachine : public StateMachine {
public:
    using StateMachine::StateMachine;

    int doSpecializedThings(){
        std::cout << "Do DerivedStateMachine things " << std::endl;
        return special_thing_;
    }

    void setState(int specialState) {
        special_thing_ = specialState;
    }

private:
    int special_thing_;
};

class AnotherDerivedStateMachine : public StateMachine {
public:
    using StateMachine::StateMachine;

    int doSpecializedThings(){
        std::cout << "Do AnotherDerivedStateMachine things and" << std::endl;
        std::cout << "\tcalling base class: ";
        StateMachine::doSpecializedThings();
        return special_thing_;
    }

    void setState(int specialState) {
        special_thing_ = specialState;
    }

private:
    int special_thing_;
};

int main()
{
    StateMachine sm;
    DerivedStateMachine dsm;
    AnotherDerivedStateMachine adsm;
    DerivedStateDependsOnGeneralStateMachine dsmg;
    DerivedStateDependsOnDerivedStateMachine dsmd;
    
    sm.setState (dsmg);

    StateMachine * pdsm = &dsm;
    pdsm->setState (dsmd);
    dsm.setState (1);

    dsmg.action (&dsm);
    dsmd.action (&dsm);

    dsmg.action (&sm);
    dsmd.action (&sm);

    dsmd.action (&adsm);
    
    return 0;
}

I don't understand why do you need the State in the StateMachine though, as you are calling StateMachine from State.

Manuel
  • 2,526
  • 1
  • 13
  • 17
0

In the end I was able to access the variables and methods I needed by casting down from the abstract to derived type

CiaranWelsh
  • 7,014
  • 10
  • 53
  • 106