0

Coming from Java to C++ I'm attempting to understand abstraction through object orientation.

To put this into a practical example, I am developing a small game using the SFML library for graphics. However this question does not relate to that, simply think of it as background info. Anyway, the way the game works is to process through a number of different states. In this case 2:

  1. The Menu State: The menu of the game is drawn and the game will begin here.

  2. The Game State: This state controls the game, will update entities and draw them.

In order to do this I have created the following classes:

GameStateManager.h

#ifndef GAMESTATEMANAGER_H
#define GAMESTATEMANAGER_H

#include <SFML/Graphics.hpp>
#include <iostream>
#include "GameState.h"

class GameStateManager
{
public:
    // Constructor
    GameStateManager();
    // State variables
    static const int NUMGAMESTATES = 2;
    static const int MENUSTATE = 0;
    static const int GAMESTATE = 1;
    // Public Functions
    void set_state(int state);
    void update();
    void draw(sf::RenderWindow &win);
    void input(sf::Event event);

private:
    // Array of gamestates
    GameState game_states[];
    // The current state
    int current_state;
    // Private functions
    void load_state(int state);
    void unload_state(int state);
};

#endif

GameState.h

#ifndef GAMESTATE_H
#define GAMESTATE_H

#include <iostream>
#include <SFML/Graphics.hpp>
#include "GameStateManager.h"

class GameState
{
protected:
    GameStateManager gsm;
public:
    virtual void init() = 0;
    virtual void update() = 0;
    virtual void draw(sf::RenderWindow &win) = 0;
    virtual void input(sf::Event event) = 0;
};

#endif

Now you may have noticed the Array of GameStates in Game State Manager? This provides an error to which I do not understand: zero-sized array. Does this mean initialization needs to be made within the header file? Further to this point the compiler mentions an Array of Abstract class isn't allowed?

The second issue is that the field gsm in the abstract GameState class does not recognize and brings up yet another error: Missing type specifier.

Now to complicate things further I have the following class: MenuState. This class is meant to extend GameState.

MenuState.h

#ifndef MENUSTATE_H
#define MENUSTATE_H

#include "GameState.h"

class MenuState: public GameState
{
public:
    MenuState(GameStateManager gsm);
    void init();
    void update();
    void draw(sf::RenderWindow &win);
    void input(sf::Event event);
private:
    sf::Texture title_texture;
    sf::Sprite title_sprite;
};

#endif

As mentioned this class will control the menu of the game.

Implementing GameStateManager is done as follows:

GameStateManager.cpp

/*
 * GameState Manager will take care of the various states of the game.
 * In particular there will be two states: Menu or Ingame. GameStateManager
 * will load and unload each state as needed.
 *
 * Author: Ben Euden
 * Date: 2/5/2014
 */

#include "GameStateManager.h"

// Class Constructor
GameStateManager::GameStateManager()
{ 
    game_states = game_states[NUMGAMESTATES];

    current_state = MENUSTATE;
    load_state(current_state);
}

/*
 * Load the current game by creating and initialising the state
 * then storing it in the game_states array.
 * @Param state The state we wish to load.
 */
void GameStateManager::load_state(int state)
{
    if(state == MENUSTATE)
        game_states[state] = MenuState(this);
    //if(state == GAMESTATE)
        //game_states[state] = MainGameState(this);    // Not implemented yet.
}

/*
 * Unload the state we loaded with load_state
 */
void GameStateManager::unload_state(int state)
{
    game_states[state] = NULL;
}

void GameStateManager::set_state(int state)
{
    unload_state(state);
    current_state = state;
    load_state(state);
}

void GameStateManager::update()
{
    try{
        game_states[current_state].update();
    }
    catch(int e)
    {
        std::cout << "Exception occured during update of game state" << e << std::endl;
    }
}

void GameStateManager::draw(sf::RenderWindow &win)
{
    try{
        game_states[current_state].draw(&win);
    }
    catch(int e)
    {
        std::cout << "Exception occured when trying to draw gamestate: " << current_state << "Exception number: " << e << std::endl;
    }
}

void GameStateManager::input(sf::Event event)
{
    game_states[current_state].input(event);
}

And MenuState as follows:

/*
 * This class extends the Game State header and will deal with the menu of the game
 * this includes drawing the correct text to the screen, moving the selector and
 * either exiting, bringing up about or starting the game.
 *
 * Author: Ben Euden
 * Date: 2/5/2014
 */

#include "MenuState.h"


MenuState::MenuState(GameStateManager gsm)
{
    gsm = gsm;
    init();

}

void MenuState::init()
{
    title_texture = sf::Texture();
    title_texture.loadFromFile("sprites/Title.png");
    title_sprite = sf::Sprite();
    title_sprite.setTexture(title_texture);
    title_sprite.setPosition(512, 200);
}

void MenuState::update(){}

void MenuState::draw(sf::RenderWindow &win)
{
    win.draw(title_sprite);
}

void MenuState::input(sf::Event event)
{

}

Please ignore inplemented methods and positionings. At this point I began to attempt to compile the project (I'm using Visual Studio) when the errors appeared.

Now in understand that the MainGameState hasn't been implemented yet but even with MenuState I'm sure I'm missing something vital here as I am still learning C++. With this in mind also please excuse any breakage of conventions etc again I am learning so feel free to correct me, it is better I learn the right way now rather than develop bad habits.

In Summary I'd like to understand why I am receiving the following errors:

protected:
    GameStateManager gsm;

This produces the error: missing ';' before gsm.

GameState game_states[];

Produces the errors of: zero-size array, array of abstract class not allowed.

I believe if I fix these the rest will sort themselves out.

Thank you for your patience, time and assistance with this.

Euden

Ben Crazed Up Euden
  • 353
  • 2
  • 7
  • 18

2 Answers2

2

To be short: you don't know any basics of C++, and as a beginner, you should really aproach it as a totally different language than Java or C, so you should stop your project right now and find a good book for C++ beginners. Don't try to mix your Java knowledge and just fill the gaps to reach C++ knowledge, it will not work because even if the syntaxe is close, they are widely different beasts.

I always recommend learning C++ as a new and different language, whatever your background. Right now you are doing big errors that shows you're on the wrong path to learn C++. You should get back to basic tutorials (I'm not trying to be harsh, you really need to learn the basics before even managing to compile this code).

You use of arrays and members like if they were references shows your lack of understanding of "value semantic" and several other basic concepts which are must-known of C++ usage.

For example, if I have

class A
{
   int k = 42;  // C++11
};

Here a A object will contain a k object. What I mean is that k is not a pointer to an int, it's the actual value, within memory allocated into the A object.

So if I have

A my_object; // object on the stack

Then my_object is an object taking the size of an int. So if I do:

class B
{
   int u;
   A a;
};

Then an instance of B will actually be the size of a A object, plus the size of an int. B objects will contain all these data in a single block of memory.

So when you do:

class GameState
{
    protected:
    GameStateManager gsm;

What you actually do here is that you build a full GameStateManager into any GameState object. Yes, gsm is not a reference, it's the full object. What you should do here is either use a c++ reference (if the game manager should never change) or use a pointer (or a smart poitner if there is ownership involved).

I see a lot of other problems, like your array member into GameStateManager have absolutely not the same meaning than in Java. Basically, you're note coding in C++ here. (and you should use either std::vector or std::array but your GameState are dynamic so it would vector or array of pointers - or even map or another container).

As there is too much to point, I should get to the core point:

Whatever the language that you have learnt before, even C or Java which are related, never ever assume you know anything of C++ yet, you absolutely don't. You need to approach it as a beginner. Learn it as a very new language.

And make sure you read actually good material as the list provided there. It's extremely easy to learn bad practice online about C++, unfortunately (but it gets better).

Also, you might want to read this: https://softwareengineering.stackexchange.com/questions/76675/how-can-a-java-programmer-make-the-most-of-a-new-project-in-c-or-c/76695#76695

By the way, a related recommendation: read "SFML Game Development" book for example of simpler and safer (and C++-idiomatic) ways to do what you are trying to achieve here.

Another side recommendation would be to avoid using "manager" in your type names, it only makes things hard to understand and design.

Community
  • 1
  • 1
Klaim
  • 67,274
  • 36
  • 133
  • 188
0

The "zero-size array" error is caused by GameState game_states[];. In C++ you have to specify the array size at declaration time, either by specifically writing the size or direct initializing it.

Example:

GameState game_states[ ]; // Error, compiler can't know how much memory to reserve for this.
GameState game_states[4]; // OK, explicit size given, compiler will reserve enough memory for 4 `GameState` objects.
GameState game_states[ ] = { GameState( ), GameState( ) }; // OK, direct initialization, compiler will reserve enough memory for 2 `GameState` object.

In your case it should be:

GameState game_states[ NUMGAMESTATES ];

And you should drop the following line from GameStateManager constructor:

game_states = game_states[NUMGAMESTATES]; // Meaningless in C++.

"Array of Abstract class isn't allowed" arises from this declaration also, the problem is C++ differs from Java here. In C++ this declares a variable which is a GameState instance, which is not allowed because GameState has pure virtual methods and as so can't be instantiated ( Just as Java abstract classes can't be newed ). To achieve this polymorphic behavior in C++ you have to use pointers or references, which is what Java uses implicit for you.

Fixing this should give you:

GameState * game_states[ NUMGAMESTATES ];

"missing ';' before gsm" is happening just because the compiler couldn't compile GameStateManager, fixing the bugs I mentioned should solve this.

Few tips:

  • Think of variables in C++ as ints from Java, even for types you've declared yourself. Which means they are instantiated just by declaring then ( no new needed ) and they are copied when assigned to another variable. ( no reference semantics by default as Java )
  • Look for good C++ books/tutorials as you don't seem to understand some very important basic concepts from C++.
Tiago Gomes
  • 386
  • 2
  • 7