I'm having a problem with circular dependencies, I suppose this is a design flaw from introducing the Game class in the wrong way.
Game.h:
#pragma once
#include <SFML\Graphics.hpp>
#include "GameScreen.h"
#include "TitleScreen.h"
class Game
{
protected:
sf::RenderWindow window;
GameScreen* CurrentGameScreen;
TitleScreen Title;
public:
Game(void);
~Game(void);
sf::RenderWindow getWindow(void);
void Run();
void Close();
};
GameScreen.h:
#pragma once
#include "Game.h"
class GameScreen
{
public:
GameScreen(void);
~GameScreen(void);
virtual void LoadAllResources() {};
virtual void DrawScreen(Game* game) {};
virtual void Update(Game* game) {};
};
TitleScreen.h:
#pragma once
#include <SFML\Graphics.hpp>
#include "GameScreen.h"
class TitleScreen : public virtual GameScreen
{
private:
sf::Texture title_screen;
sf::Sprite titleScreen;
sf::Font font;
sf::Text menuExit;
public:
TitleScreen(void);
~TitleScreen(void);
void LoadAllResources();
void DrawScreen(Game* game);
void Update(Game* game);
};
Then there's the main file:
#include "Game.h"
int main()
{
Game game;
game.Run();
//sf::RenderWindow window(sf::VideoMode(800, 600), "Test");
//GameScreen* currentScreen;
//TitleScreen titleScreen;
//currentScreen = &titleScreen;
//while (window.isOpen())
//{
// currentScreen->Update(&window);
// currentScreen->DrawScreen(&window);
//}
return 0;
}
GameScreen.h and TitleScreen.h raise a handful of C2061. From what I understand these are caused by circular dependencies between Game.h and Gamescreen.h.
TitleScreen.h is giving me error C2504: 'GameScreen' : base class undefined.
Game.h: on lines 12 and 13, give C2143: syntax error : missing ';' before '*', although I'm not sure where this is coming from and my IDE is not giving me any syntax errors.
If I remove the #include statement from GameScreen.h and substitute it with a forward declaration class Game; (which I guess breaks the circular dependency?) most of the above is solved, but TitleScreen.cpp throws a set of C2027, C2227 and C2228 (undefined type, left of -> and left of .) every time I try to access a Game object. IntelliSense points out that a pointer to an incomplete class is not allowed.
I got it working before introducing the Game class - DrawScreen() and Update() would take as argument a pointer to window (sf::RenderWindow* window). There's part of the old code left in main.cpp.
In the GameScreen.h you should declare the Game class instead of including its whole header file, so this:
class Game;
instead of:
#include "Game.h"
Related
This question already has answers here:
How are circular #includes resolved?
(4 answers)
Closed 2 years ago.
I get GameObject: base class undefined while trying to compile. I don't see anything wrong. I have a parent-child relationship between GameObject and player:
GameObject.h
#pragma once
#include "Game.h"
class GameObject
{
protected:
int x, y;
SDL_Texture* objTexture;
SDL_Rect srcRect{}, destRect{};
public:
GameObject(const char* textureSheet, int p_x, int p_y);
~GameObject();
void Update();
void Render();
};
Player.h
#pragma once
#include "GameObject.h"
class Input;
class Player : public GameObject
{
private:
Input* input{ nullptr };
public:
Player(Input * p_input);
~Player();
void Update();
};
This is Game.h
#pragma once
#include <SDL.h>
#include <SDL_image.h>
#include "TextureManager.h"
#include "Player.h"
#include "Map.h"
#include "Input.h"
class Player;
class Map;
class Input;
class Game
{
private:
SDL_Window* window{ nullptr };
Player* player{ nullptr };
Input* input{ nullptr };
Map* map{ nullptr };
bool isRunning = false;
public:
Game();
Game(const char* title, int xPos, int yPos, int width, int height, bool fullscreen);
~Game();
void HandleEvents();
void Update();
void Render();
void clean();
bool running() { return isRunning; };
static SDL_Renderer* renderer;
};
most of the discussion I have seen says that this is due to some repeated includes which create circular dependencies, but I don't see any problem with that. is this something to do with the game class?
It would help if you gave us the exact error message and pointed to the line number.
I suspect this is because your GameObject has a constructor that requires arguments but your Player class does not provide these arguments in its constructor initialization list.
But this is just a guess.
A new guess!
The #include "Game.h" in your GameObject.h is the problem.
Only ever include what you use, and never create circular references even if you use #pragma once That pragma doesn't do what some people think it does.
Instead of Game.h include the SDL headers you require.
Whenever possible remove header includes from header files and use forward declarations of anything that is a pointer. Include the header for the concrete definitions only in your source files (the .cpp files).
You really want to avoid the problem of including one header and having it pull in a huge web of 500 other include files.
You are going to need the SDL header in order to use SDL_Rect though.
The easy way is to forward declare the missing class prototypes.
class SDL_Texture;
class SDL_Rect;
As you have already started on in Player.h
A more defensive way is to always include all headers needed in every source file.
#include <SDL.h>
or another SDL header.
And you have already solved the circular include with the
#pragma once
I have three classes, 2 of which rely on the functionality of each other, and one which contains pointers to and is included in both:
Player:
#pragma once
#include <SFML\Graphics.hpp>
#include "RenderableObject.h"
//#include "Renderer.h"
class Renderer;
class Player : public RenderableObject
{
public:
Player(int size, Renderer* renderer);
~Player();
void render();
void setX(int x);
void setY(int y);
int getX();
int getY();
void setVelX(float x);
void setVelY(float y);
float getVelx();
float getVely();
int getSize();
private:
int size;
int x;
int y;
float velx;
float vely;
Renderer* ren;
};
GameManager:
#pragma once
#include "Player.h"
class Renderer;
class GameManager
{
public:
GameManager(Renderer* r);
~GameManager();
Player* getBall();
private:
Player* ball;
};
Renderer:
#pragma once
#include <SFML\Graphics.hpp>
#include "GameManager.h"
#include "Player.h"
class Renderer
{
public:
Renderer(GameManager* game);
~Renderer();
sf::RenderWindow* getWindow();
void draw();
void renderCircle(int size, int x, int y);
void renderSquare(int size, int x, int y);
private:
sf::RenderWindow* win;
GameManager* game;
Player* ball;
};
I suspect there is some sort of circular dependency going on here. I managed to reduce the 60 odd errors down to 3, by adding "class Renderer;" to the Player header file. However, I'm now receiving "Use of undefined type" errors.
It might help to give a higher level view of what I want to achieve:
The GameManager object should hold an instance (maybe more) of player. This GameManager object is shared between subsystems such as Renderer so they all have access to the same resources.
The Renderer object should be able to call the Player object's (retrieved from the GameManager object) render() function, which in turn should call back to the Renderer object's renderCircle() object.
I'm hoping this is a simple case of re-arranging the includes, without having to re-design what I've already done.
In a header file, where you only declare variables that are pointers or references, all the compiler needs to know is that a class exists, nothing more. It doesn't need to know how big it it, or what members the class have. Therefore it's enough with a forward declaration.
However, in the source files where the variable is used, objects are created, and member functions are called, then the compiler need the full definition which means you have to include your whole header file.
Taking your code, simplified:
Player.h
#pragma once
class Renderer;
class Player
{
public:
Player(Renderer*);
private:
Renderer* ren;
};
GameManager.h
#pragma once
class Renderer;
class GameManager
{
public:
GameManager(Renderer*);
private:
Renderer* ren;
};
Renderer.h:
#pragma once
class Player;
class GameManager;
class Renderer
{
public:
Renderer(GameManager*);
private:
GameManager* game;
Player* ball;
};
The above header files are about the same that you already have, with the exception that I used forward declarations in Renderer.h instead.
Now the Renderer.cpp source file, where the Player and GameManager objects are actually created and used, we need the full definition from the header files:
#include "Renderer.h"
#include "Player.h"
#include "GameManager.h"
Renderer::Renderer(GameManager* game)
: game(game), ball(new Player)
{
}
// Other functions that calls member function in the `man` and `ball` objects
Of course, you need to #include "Renderer.h" in the Player.cpp and GameManager.cpp source files.
If you have other errors, they are because of other things you done, not because of the circular dependencies, as those have been solved with the forward declarations.
So, I'm having what is likely a pretty simple problem, but I can't seem to figure out what is causing it.
I have a C++ class called "Game" consisting of a class declaration in Game.h
and a source definition in Game.cpp.
I have included "Game.h" in my "Game.cpp", but for some reason Visual Studio doesn't seem to recognize the class declarations within Game.h.
I'd appreciate any help I could get trying to figure out why this is the case, and why I am getting the following errors:
'MyCharacter' : undeclared identifier and 'HandleKeyPressed' : identifier not found.
Game.h:
------------------------------------------------------------------------------------------------------------------
#pragma once
#ifndef Game_Header
#define Game_Header
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include "Character.h"
#include "FloorPlatform.h"
class Game
{
public:
Game();
~Game();
int Run();
void HandleKeyPressed(sf::Keyboard::Key);
Character MyCharacter;
};
#endif // !Game_Header
Abridged Game.cpp
#include "Game.h"
Game::Game()
{
}
Game::~Game()
{
}
int Run(){
sf::RenderWindow MainGameWindow(sf::VideoMode::getDesktopMode(), "A Test Game");
//Start Game Loop
while (MainGameWindow.isOpen()){
while (MainGameWindow.pollEvent(event)){
//Handle some other events here...
if (event.type == sf::Event::KeyPressed){
HandleKeyPressed(event.key.code);
}
}
MainGameWindow.clear(sf::Color::White);
MyCharacter.Instance.Circle.setPosition(MyCharacter.PlayerLocation);
MainGameWindow.draw(MyCharacter.Instance.Circle);
MainGameWindow.display();
}
return 0;
}
void HandleKeyPressed(sf::Keyboard::Key PressedKey){
switch (PressedKey)
{
case sf::Keyboard::A:
MyCharacter.PlayerLocation.x -= 16;
break;
}
}
Full code can be found here:
http://pastebin.com/x6KhDxgL
Thanks in advance for any help I can get with this.
Try
int Game::Run()
instead of
int Run()
in Game.cpp, the same for HandleKeyPressed, because it's the method of the Game class. Depending on your Character.h you may need to initialize MyCharacter, too.
void HandleKeyPressed(sf::Keyboard::Key PressedKey){
In Game.cpp should be
void Game::HandleKeyPressed(sf::Keyboard::Key PressedKey){
Same for int run()
(I have read all the threads posted here and google, I was not able to fix from that)
I am having toruble with a incomplete type error when compiling. The way I am designing the project, the game pointer is unavoidable.
main.cpp
#include "game.h"
// I actually declare game as a global, and hand itself its pointer (had trouble doing it with "this")
Game game;
Game* gamePtr = &game;
game.init(gamePtr);
game.gamePtr->map->test(); // error here, I also tested the basic test in all other parts of code, always incomplete type.
game.h
#include "map.h"
class Map;
class Game {
private:
Map *map;
Game* gamePtr;
public:
void init(Game* ownPtr);
int getTestInt();
};
game.cpp
#include "game.h"
void Game::init(Game* ownPtr) {
gamePtr = ownPtr;
map = new Map(gamePtr); // acts as "parent" to refer back (is needed.)
}
int Game::getTestInt() {
return 5;
}
map.h
class Game;
class Map {
private:
Game* gamePtr;
public:
int test();
};
map.cpp
#include "map.h"
int Map::test() {
return gamePtr->getTestInt();
}
// returns that class Game is an incomplete type, and cannot figure out how to fix.
Let's go over the errors:
1) In main, this is an error:
game.gamePtr->map->test();
The gamePtr and map are a private members of Game, therefore they cannot be accessed.
2) The Map is missing a constructor that takes a Game* in Game.cpp.
map = new Map(gamePtr);
Here is a full working example that compiles. You have to provide the functions that are missing bodies, such as Map(Game*).
game.h
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
class Map;
class Game {
private:
Map *map;
public:
Game* gamePtr;
void init(Game* ownPtr);
int getTestInt();
};
#endif
game.cpp
#include "game.h"
#include "map.h"
void Game::init(Game* ownPtr) {
gamePtr = ownPtr;
map = new Map(gamePtr); // acts as "parent" to refer back (is needed.)
}
int Game::getTestInt() {
return 5;
}
map.h
#ifndef MAP_H_INCLUDED
#define MAP_H_INCLUDED
class Game;
class Map {
private:
Game* gamePtr;
public:
int test();
Map(Game*);
};
#endif
map.cpp
#include "game.h"
#include "map.h"
int Map::test() {
return gamePtr->getTestInt();
}
main.cpp
#include "game.h"
#include "map.h"
int main()
{
Game game;
Game* gamePtr = &game;
game.init(gamePtr);
game.gamePtr->map->test();
}
After doing this and creating a project in Visual Studio, I do not get any errors building the application.
Note the usage of #include guards, which your original posted code did not have. I also placed the members that were private and moved them to public in the Game class, so that main() can compile successfully.
You need to use forward declaration. Place declaration of Map class before definition of class Game:
game.h
class Map; // this is forward declaration of class Map. Now you may have pointers of that type
class Game {
private:
Map *map;
Game* gamePtr;
public:
void init(Game* ownPtr);
int getTestInt();
};
Every place where you use Map and Game class by creating instance of it or dereferencing pointer to it either through -> or * you have to make that type "complete". It means that main.cpp must include map.h and map.cpp must include game.h directly or indirectly.
Note you forward declare class Game to avoid game.h to be included by map.h, and that is fine and proper, but map.cpp must have game.h included as you dereference pointer to class Game there.
My header for my class is
#ifndef _CENGINE_H
#define _CENGINE_H
#include "SFML\Graphics.hpp"
#include "CTextureManager.h"
#include "CTile.h"
class CEngine
{
private:
//Create instance of CTextureManager
CTextureManager textureManager;
//Load textures
void LoadTextures();
//New tile
CTile* testTile;
bool Running; //Is running?
sf::RenderWindow* window; //Create render window
public:
CEngine(); //Constructor
int Execute(); //Execute
bool OnInit(); //On intialization
void GameLoop(); //Main game loop
void Render(); //Render function
void Update(); //Update
};
#endif
Now the 3 errors it's giving me with this are:
cengine.h(8): error C2236: unexpected 'class' 'CEngine'. Did you forget a ';'?
cengine.h(8): error C2143: syntax error : missing ';' before '{'
cengine.h(8): error C2447: '{' : missing function header (old-style formal list?)
I know the errors are obvious but I can't see a problem with the class. I'm probably being really stupid because I'm tired.
It seems like a circular include issue. Do CTextureManager.h or CTile.h include each other or CEngine.h?
To solve this, use forward declarations where possible. For example, your class doesn't need to include CTile.h - it can look like:
#ifndef CENGINE_H
#define CENGINE_H
#include "SFML\Graphics.hpp"
#include "CTextureManager.h"
class CTile; //forward declaration instead of include
class CEngine
{
private:
//Create instance of CTextureManager
CTextureManager textureManager;
//Load textures
void LoadTextures();
//New tile
CTile* testTile;
bool Running; //Is running?
sf::RenderWindow* window; //Create render window
public:
CEngine(); //Constructor
int Execute(); //Execute
bool OnInit(); //On intialization
void GameLoop(); //Main game loop
void Render(); //Render function
void Update(); //Update
};
#endif
Similar for the other 2 headers.
Also, _CENGINE_H is not a valid identifier - note how I renamed it to CENGINE_H.