Problems with inherited constructor variable initialization.

Nov 22, 2011 at 4:34am
Hello!

(Before I get into asking my question, please note that I am a very inexperienced programmer. So, please excuse me if I do not communicate the trouble I am having very well. Thanks!)

Long, story shorter, I am trying to program a finite state machine. My code compiles but I can't get it to run right yet. I have a GameState class that has has public methods and private data necessary for the methods to operate. Each state that I have derives from the GameState class. It only inherits the public stuff in the bass class.


I have stepped through it with a debugger a few times and as best as I can tell this is what happens:

When I run the main funtion, a GameClass object is created, and its default constructor intializes the private data. The compiler complains if I try to initialize the variables in the header file instead of using the constructor.

Soon after the state machine calls the constructor for one of the derived classes to create an instance of it. This results in the default constructor of the base class being called.

The base constructor then tries to initialize the private data. Since this is not inherited by the derived class it overwrites the private variables that where originally declared when the GameState object was first constructed.

This causes the private variable indicating the state to switch to as NULL and the state never changes, so it gets stuck in an infinite loop.


I could have the constructor for the GameState class take an arbitrary parameter so it is not the default constructor to avoid reinitilaizng the data when trying to consitruct derived objects. That seems like a very contrived, and lame, fix though.

Here is some of the code to get how the program runs. Perhaps it will be clearer then my explanation:

Main function(TestMain.cpp):
1
2
3
4
5
6
7
8
9
10
#include "TestMachine.h"
#include "TestMachine.cpp"
using namespace std;

int main() {
  GameState *machine;
  machine = new GameState();
  machine->runLoop();
  delete machine;
}


TestMachine.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
l
#ifndef TESTMACHINE_H
#define TESTMACHINE_H
using namespace std;

enum State {
  STATE_NULL,
  STATE_ONE,
  STATE_TWO,
  STATE_THREE,
  STATE_EXIT
};

class GameState
{

  public:
    GameState();
    virtual void handleInput(){};
    virtual void runLogic(){};
    virtual void displayOutput(){};
    virtual ~GameState(){};

    void runLoop();
    void setNextState(int newState);
    void changeState();

  private:

    int stateId;
    int nextState;

    GameState *currentState;
};

#endif 


TestMachine.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "TestMachine.h"
#include "StateOne.cpp"
#include "StateTwo.cpp"
#include "StateThree.cpp"
using namespace std;


GameState::GameState(){
    stateId   = STATE_NULL;
    nextState = STATE_NULL;
    currentState = NULL;
}

void
GameState::setNextState(int newState) {
  bool isContinue = (nextState != STATE_EXIT);
  if (isContinue) {
    nextState = newState;
  }
}


void
GameState::changeState() {

  // This is the check that keeps it stuck in the while loop
  // Since each time a constructor is called nextState is set to STATE_NULL;
  bool shouldChange = (nextState != STATE_NULL);
  if (shouldChange) {

    bool isContinue = (nextState != STATE_EXIT);
    if (isContinue) {

      delete currentState;
    }

    switch(nextState) {

      case STATE_ONE:
        currentState = new StateOne();
        break;

      case STATE_TWO:
        currentState = new StateTwo();
        break;

      case STATE_THREE:
        currentState = new StateThree();
        break;

    }

    stateId = nextState;

    nextState = STATE_NULL;

  }

}

void
GameState::runLoop() {

    stateId = STATE_ONE;

    currentState = new StateOne();

    while(stateId != STATE_EXIT ) {

        currentState->handleInput();
        currentState->runLogic();

        changeState();

        currentState->displayOutput();

    }

  if(currentState != NULL) {
    delete currentState;
  }
}


For some reason it also is not displaying strings using iostream::cout, instead I get a blank line in the terminal each time I try to do this; But this may be an unrelated bug.

If you bothered to read this far you are a very patient person! If anyone has any help or suggestions I would be very grateful! :)

Thank you!
Last edited on Nov 22, 2011 at 4:41am
Nov 22, 2011 at 5:25am
[the base class' data] is not inherited by the derived class
This is false. All derives classes inherit the base's data. A lot of things wouldn't make sense if this was not the case.

The most likely situation from what you've said is that your derived constructors aren't calling the base constructor with
 
Derived::Derived():Base(){ /*...*/ }
so the data doesn't get initialized.
If this is not it, post the definition and implementation of StateOne.

it overwrites the private variables that where originally declared when the GameState object was first constructed.
Just out of curiosity (one of my hobbies is dissecting incorrect reasonings so I can understand, and hopefully avoid, them), what exactly do you mean by this?
Nov 22, 2011 at 6:37am
Hi helios,

Thank you for your reply.


This is false. All derives classes inherit the base's data. A lot of things wouldn't make sense if this was not the case.


So you are saying that even the private data of the base class is inherited in the derived class? I'm not sure I understand.


Just out of curiosity (one of my hobbies is dissecting incorrect reasonings so I can understand, and hopefully avoid, them), what exactly do you mean by this?

I don't know. When I step through the code with a debugger, everything works fine until I step through the base class constructor when it is called during the creating of an instance of one of the derived classes. Before then when I check the value of the nextState variable it is whatever it should be, but after calling the constructor, it is set back to the value the base class contructor initializes it to.

It is very likely that my diagnoses of the problem is way off; I really don't know what I'm doing yet.


Here is the declaration and implementation of StateOne:

StateOne.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef ONE_H
#define ONE_H
#include "TestMachine.h"
#include <iostream>
#include <string>
using namespace std;

class StateOne : public GameState
{
  public:

    StateOne();

    void handleInput();
    void runLogic();
    void displayOutput();

  private:

    char input;

    string options;
    string prompt;
    string output;

};

#endif 


StateOne.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "StateOne.h"
#include <iostream>
#include <string>
using namespace std;


StateOne::StateOne() {
    input = 'e';
    string options = "\nEnter: 1, 2, or 3 to switch to respective state.\nAlso n for next and q for quit\n";
    string prompt  = "\nEnter option: ";
    string output  = "\nThis is test state one.\n";
}

void
StateOne::handleInput() {
    bool needsInput = (input == '0');
    if (needsInput) {
      cout << prompt;
      cin  >> input;
    }
}
      
void
StateOne::runLogic() {
  bool isInput = (input != 'e');
  if(isInput) {
    switch(input) {
      case 0:
        break;

      case 1:
        setNextState(STATE_ONE);
        break;

      case 2:
        setNextState(STATE_TWO);
        break;

      case 3:
        setNextState(STATE_THREE);
        break;

      case 'n':
        setNextState(STATE_TWO);
        break;

      case 'q':
        setNextState(STATE_EXIT);
        break;

      default:
        break;
    }
  }
  input = '0';
}

void
StateOne::displayOutput() {

  cout << endl << output << endl << options << endl;
}



The other two states work exactly the same way. This state machine doesn't actually do anything except switch between them and let me know which state I am in, I was just trying to make one for its own sake so I could learn how for another project and future use beyond that.
Nov 22, 2011 at 10:53am
So you are saying that even the private data of the base class is inherited in the derived class?
Correct.

It looks to me like the program is behaving in exactly the way you told it to. Perhaps you're confused about the semantics.
This is what happens when you create a StateOne:
1. sizeof(StateOne) bytes are allocated for the object. If the object exists on the stack or in static space, this involves doing nothing.
2. StateOne::StateOne() is called, but its body (the part between braces) is not yet entered.
3. Most implementations will call the default base class constructor at this point if one is defined but no call to any of its overloads is in the initialization list. This is not required by the standard, IINM.
4. If the previous step did nothing or isn't performed by the implementation, the base class constructor is called as specified in StateOne::StateOne()'s initialization list.
5. GameState::GameState() runs completely (everything on this list starting from step 2).
6. The rest of StateOne::StateOne()'s initialization list is run.
7. The body of StateOne::StateOne() is entered.
8. After StateOne::StateOne() returns but before control is returned to the caller, the virtual table is initialized. Polymorphic calls inside constructors don't behave as you'd intuitively expect.
9. Control is returned to the caller.
Nov 22, 2011 at 6:30pm

It looks to me like the program is behaving in exactly the way you told it to. Perhaps you're confused about the semantics.
This is what happens when you create a StateOne:


Of course it does what I told it to! I just didn't tell it the right thing to accomplish what I'm trying to. I'm not accusing the compiler of doing something wrong, just myself. I'm trying to figure out what I'm doing wrong here.

This is what I'm trying to figure out:
What is the best ways I initialize the private variables in the GameState class and then later create a State object without this test returning false when I don't want it to:
1
2
3
  bool shouldChange = (nextState != STATE_NULL);
  if (shouldChange) {
    //... 



This is what happens when you create a StateOne:


That is very helpful, thanks!

I was not understanding why my changeState function fails each iteration of the while loop. All I know is that the nextState variable is set back to null each iteration of the while loop.

Now, I've slept on the problem a bit and I realized what may be going wrong:

In the main while loop, when I run currentState->runLogic(); and then it runs setNextState(newState), StateOne.nextState is getting set to the newState, not GameState.nextState like I intended.

Then in the main loop when changeState runs and checks for whether nextState is STATE_NULL or some other value it finds it is STATE_NULL because it was never changed. I only changed StateOne.nextState not GameState.next state. I forgot the setNextState() procedure is public so the derived class inherits it.

It was stupid of me for going so long without noticing that! Anyway let me know what you think.

Thanks so much for all your help!

Nov 22, 2011 at 7:03pm
StateOne.nextState is getting set to the newState, not GameState.nextState
It's the same thing. More accurately, there's no such thing as StateOne::nextState, only GameState::nextState, but the member is accessible by derived classes if it's protected or public.
I recommend you read up on inheritance before trying to proceed, because you're obviously very confused about what it does.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

class A{
protected:
    int value;
public:
    A(int x):value(x){}
    virtual int get(){ return value; }
};

class B:public A{
public:
    B(int x):A(x){}
    int get(){ return value+1; }
};

int main(){
    B b(42);
    A &a=b;
    std::cout <<a.A::get()<<std::endl
        <<a.get()<<std::endl
        <<b.get()<<std::endl;
}
Nov 22, 2011 at 7:39pm

It's the same thing. More accurately, there's no such thing as StateOne::nextState, only GameState::nextState, but the member is accessible by derived classes if it's protected or public.
I recommend you read up on inheritance before trying to proceed, because you're obviously very confused about what it does.


Oh, wow! I guess I do not understand inheritance nearly as well as I thought I did! :(

Your code example was helpful, though. I ran it and it illustrated how it works nicely.

So when I create a derived class object and the constructor is called, it calls the default base constructor.
In my case this constructor initializes variables so they are reset to that value when this part happens.
Later I call the setNextState procedure and the GameState::changeState variable is modified.
Then the GameState->changeState procedure is called.
This checks the value of nextState and behaves accordingly.

But for some reason I do not yet understand, no matter what setNextState set the nextState variable to it always ends up as STATE_NULL(or 0) by this point.

I guess I will hit the tutorials and documentation some more to see if I can learn whatever it is I am not getting here.
Nov 24, 2011 at 6:44am
Probably no one is reading this anymore, but in case anyone is I should update:

Victory is mine, finally! Actually, the solution was so simple I am really an idiot for even having the problem in the first place. I owe you an apology for wasting your time with my incompetence, Helios.

I was not clearly thinking about the distinction between objects and classes. All I needed to do was this:

GameState.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//....

void
GameState::runLoop() {

    stateId = STATE_ONE;

    currentState = new StateOne();

    while(stateId != STATE_EXIT ) {

        currentState->handleInput();
        currentState->runLogic();

        nextState = currentState->nextState; //Tada! Duh!
        changeState();

//.... 


Moral of the story: Idiocy is not conducive to good programming so avoid it!
Topic archived. No new replies allowed.