PrimRock PrimRock - 3 months ago 11
C++ Question

Stack returning copy because of inheritance?

I'm having a bit of trouble trying to get my stack container adaptor to return from a getter by reference. Every time I try to make a getter to it even when using the reference operator it seems to be making a copy of it. I say this because whenever I debug and watch the container in one class the size of the container is 1 as expected since I pushed an object to the stack. However, once I enter another class via function...that class changes the size of the stack back to 0. Until I return back to what invoked the function then it returns back to 1.

Is it because I'm inheriting from the class that uses the container ?. Which goes on to my next question...Does inheritance make copies of the members in the mother class or does it reference them ? I'll try to explain this with minimal code so please be nice...


GAME.HPP


#ifndef GAME_HPP
#define GAME_HPP

#include <stack>
#include "GameState.hpp"

class Game
{
public:
Game();
~Game();

int playGame();

protected:
std::stack<GameState*>& getGStates();

private:
std::stack<GameState*> gameStates; //GameState is a abstract class (no implementation)
bool gameRunning;
};

#endif



GAME.CPP


int Game::playGame()
{
gameRunning = true;

SplashScreen sScreen; // SplashScreen inherits from GameState class
gameStates.push(std::move(&sScreen)); //move screen to stack without making a copy

// The stack size is now 1

while (gameRunning)
{
gameStates.top()->runState();
}
return 0;
}

std::stack<GameState*>& Game::getGStates()
{
return gameStates; //returns stack
}



GAMESTATE.HPP


#ifndef GAMESTATE_HPP
#define GAMESTATE_HPP

class GameState
{
public:
GameState(){};
~GameState(){};

virtual void runState() = 0;
virtual void resumeState() = 0;
virtual void pauseState() = 0;
virtual void update() = 0;
virtual void render() = 0;
};
#endif


I do provide a good amount of implementation in the
SplashScreen
class, but if I remove it the problem will still persist. So for now to keep it simple I'll just say that its really no more different than what you see in the
GameState
header, but with blank blocks and returns. I'll still show the
runState()
bit but simplify it to scope the problem.


SPLASHSCREEN.CPP


//obvious header includes above

void SplashScreen::runState()
{
std::cout << getGStates() << std::endl; //here the stack is 0
std::cin.get(); //getting char from input stream so program won't terminate so fast
return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
}


One thing that I want to mention though is that the
SplashScreen
class does indeed inherit from
GameState
and the
Game
class. I inherit from the
GameState
class so I can use it as a interface for my
SplashScreen
class, and I inherit from the
Game
class so I can use the getter method.

Your probably saying why won't I just pass by reference through the function
runState()
in
Game.cpp
. I can and it'll work, but is there another way to do it without cluttering my function with parameters ? I don't want to have to add a parameter in every time I need something. Then again if I'm doing that my object design is poor, right ? Please help...

Answer

You mentioned that SplashScreen inherits from Game. Therefore, the following code:

void SplashScreen::runState()
{
    std::cout << getGStates() << std::endl; //here the stack is 0
    std::cin.get(); //getting char from input stream so program won't terminate so fast
    return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
}

prints the stack for the Splashscreen instance object, not the initial Game instance object. In other words, the stack you print is not the same one you pushed the SplashScreen object to, or even a copy of that, but a completely unrelated GameState stack.

Your problem is: inheritance is not the right way to reason about the relationship between a Game and a SplashScreen. Inheritance mostly model "is a kind of" relationships between classes, and it looks like a SplashScreen is probably not a kind of Game. The kind of relationship you want to represent is a usage relationship, represented by referencing the object you're going to be using or passing it as parameter somewhere in the callstack.

If you need to access the game, you should probably:

  1. add it as a member variable in your SplashScreen class, e.g.

    //Splashscreen.h
    class SplashScreen : public GameState {
        public:
        SplashScreen(Game& game)
        : m_game(game) {
        }
    
        ...    
    
        private:
        Game& m_game;
    }
    
    //SplashScreen.cpp
    void SplashScreen::runState()
    {
        std::cout << m_game.getGStates() << std::endl; //here the stack is 0
        std::cin.get(); //getting char from input stream so program won't terminate so fast
        return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
    }
    
  2. or pass it as an argument to your runState method, e.g.

    void SplashScreen::runState(Game& game)
    {
        std::cout << game.getGStates() << std::endl; //here the stack is 0
        std::cin.get(); //getting char from input stream so program won't terminate so fast
        return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
    }
    
Comments