0

first time in Stackoverflow! I am quite new in C++ and OOP and I am currently struggling with a problem when trying to design a StateChart in C++.

I have found some documentation explaining how to create a State Machine with n-states and an example of code simulating the transitions Red-Green-Yellow in a traffic light.

I report the code below:

Header

class TLState
{
  public:
     virtual void Handle() = 0;
};

class TLNetTraffic
{
    private:
        TLState* _state;
    public:
        TLNetTraffic();
        void setState ( TLState* state );
        void Handle();
};

class TLRed: public myTLState
{
    private:
        TLNetTraffic* _context;

    public:
        TLRed(TLNetTraffic* context);
        void Handle();
};

class TLGreen: public TLState
{
    private:
        TLNetTraffic* _context;

    public:
        TLGreen(TLNetTraffic* context);
        void Handle();
};

class TLYellow: public TLState
{
    private:
        TLNetTraffic* _context;

    public:
        TLYellow(TLNetTraffic* context);
        void Handle();
};

cpp

#include "classes.h"
#include <iostream>

TLNetTraffic::TLNetTraffic()
{
    _state = new TLRed(this);
}

void TLNetTraffic::setState ( TLState* state )
{
    _state = state;
}

void TLNetTraffic::Handle ()
{
    _state->Handle();
}

TLRed::TLRed(TLNetTraffic* context): _context(context) {}

void TLRed::Handle()
{
    std::cout << "Red Light" << std::endl;
    _context->setState( new TLGreen(_context) );
}

TLGreen::TLGreen(TLNetTraffic* context): _context(context) {}

void TLGreen::Handle()
{
    std::cout << "Green Light" << std::endl;
    _context->setState( new TLYellow(_context) );
}

TLYellow::TLYellow(TLNetTraffic* context): _context(context) {}

void TLYellow::Handle()
{
    std::cout << "Yellow Light" << std::endl;
    _context->setState( new TLRed(_context) );
}

There is my question: I would like to extend such example with sub-states for each upper state, for instance Red_1, Red_2, Red_3, Green_1, Green_2, Green_3, Yellow_1, Yellow_2, Yellow_3...

Now, the easiest thing I have in mind is to "consider" all the states at the same level and to use the structure reported above. Personally, I do not like this solution and I was wondering whether a nicer design could be implemented. I tried to modify the code as follows (I report only the "red" class):

class myTLState
{
  public:
     virtual void Handle() = 0;
};

class myTLState_internal //NEW VIRTUAL CLASS
{
  public:
     virtual void Handle() = 0;
};

class myTLNetTraffic
{
    private:
        myTLState* _state;
    public:
        myTLNetTraffic();
        void setState ( myTLState* state );
        void Handle();
};

class myTLRed: public myTLState
{
    private:
        myTLNetTraffic* _context;
        myTLState_internal* _internal_state; //NEW POINTER TO THE NEW VIRTUAL CLASS

    public:
        myTLRed(myTLNetTraffic* context);
        void Handle();
        void setState ( myTLState_internal* _internal_state );
};

class myTLRed_internal1: public myTLState_internal
{
    private:
        myTLRed* _internal_context;

    public:
        myTLRed_internal1(myTLRed* context);
        void Handle();
};

class myTLRed_internal2: public myTLState_internal
{
    private:
        myTLRed* _internal_context;

    public:
        myTLRed_internal2(myTLRed* context);
        void Handle();

};

I added in the cpp the following:

myTLRed::myTLRed(myTLNetTraffic* context): _context(context)
{
         _internal_state = new myTLRed_internal1(this);
}

myTLRed_internal1::myTLRed_internal1(myTLRed* context): _internal_context(context){}

I get the following error message: undefined reference to 'vtable for myTLRed_internal1'

Honestly, no idea neither what that is nor if this is the right way. Any help would be really appreciated. Thanks a lot and sorry for the long post.

EDIT for all those pointing out there is a lot of memory leak: you are completely right, I was aware of that but reported only the code as I have found it for sake of simplicity. Next improvement to avoid memory leak would be to use smart pointers, that's my plan.

  • If the question if about the error message, i.e. `vtable for myTLRed_internal1`, make sure that ALL virtual functions of this class have an implementation. – TonySalimi Apr 20 '20 at 21:03
  • `_internal_state = new myTLRed_internal1(this);` where do you declare the `myTLRed_internal1` class? Before you first try to use it? Also all of this passing of pointers and dynamically allocating memory is overkill. All you need for a statemachine is an enum for all your states and a switch to execute each state. – JohnFilleau Apr 20 '20 at 21:03
  • You have a lot of memory leaks here. Every time you assign a member point to `new` anything, you don't `delete` the prior pointer. – JohnFilleau Apr 20 '20 at 21:10
  • Programming a state machine is the only legitmate use of `goto`, each goto label is a state. – john Apr 20 '20 at 21:10
  • @JohnFilleau: I edited the post explaing I would improve it using smart pointers, as far as I understood I should avoid memory leak in this way. Regarding the other question, it is in the cpp right after, so it might be the issue. Then my question is why it works for the upper level (I have first the constructor TLNetTraffic that allocates memory with the constructor of TLRed, that is defined after in the code). Last thing, I exactly want to avoid the switch structure and this was the only example I found on the net. – WTI_Carmelo Apr 20 '20 at 21:25

0 Answers0