How to initialize all variables from a namespace in one class - c++

I am making a small game using SFML.
I want to load all my resources in one go when the game launches, so every time a new entity is created new resources don't need to be loaded to memory slowing down the game.
I have made a header file with a namespace for each kind of resource I need:
#pragma once
#include <SFML/Graphics.hpp>
#include <iostream>
#include "spritesheet.h"
namespace PlayerSprite {
extern Spritesheet playerSpritesheet;
extern sf::Sprite sp1, sp2, sp3, sp4, sp5, sp6;
extern int width = 16;
extern int height = 16;
}
namespace ButtonSprite {
extern Spritesheet buttonSpritesheet;
extern sf::Sprite button;
extern int width = 32;
extern int height = 16;
}
class Resources {
public:
Resources() = default;
void loadResources();
};
Now I don't know much about namespaces only very basic stuff, this is the first reason to use one.
Now in the cpp file:
#include <iostream>
#include "../headers/resources.h"
void Resources::loadResources() {
// PLAYER
PlayerSprite::playerSpritesheet.setSprite("./res/img/tiles.png");
PlayerSprite::sp1 = PlayerSprite::playerSpritesheet.getSprite(0, 0, PlayerSprite::width,
PlayerSprite::height);
PlayerSprite::sp2 = PlayerSprite::playerSpritesheet.getSprite(32, 0, PlayerSprite::width,
PlayerSprite::height);
PlayerSprite::sp3 = PlayerSprite::playerSpritesheet.getSprite(48, 0, PlayerSprite::width,
PlayerSprite::height);
PlayerSprite::sp4 = PlayerSprite::playerSpritesheet.getSprite(64, 0, PlayerSprite::width,
PlayerSprite::height);
PlayerSprite::sp5 = PlayerSprite::playerSpritesheet.getSprite(80, 0, PlayerSprite::width,
PlayerSprite::height);
PlayerSprite::sp6 = PlayerSprite::playerSpritesheet.getSprite(0, 16, PlayerSprite::width,
PlayerSprite::height);
// PLAYER
// BUTTONS
ButtonSprite::buttonSpritesheet.setSprite("./res/img/tiles.png");
ButtonSprite::button = ButtonSprite::buttonSpritesheet.getSprite(48, 16, 32, 16);
// BUTTONS
}
I then call this function in the main game file, but when I run I get this error in the player class:
undefined reference to 'PlayerSprite:sp1'
I don't know if this is because of the namespace declaration, or me coding the system wrong.
After looking at some comments on this question I have added this:
void Resources::allocateStorage() {
sf::Sprite PlayerSprite::spritesheet;
sf::Sprite PlayerSprite::sp1;
}
In the cpp file, but I am now getting this error:
unqualified-id in declaration before ';' token on the 1st line after the implementation of the function.

The problem seems to be that the variables are not actually defined anywhere, just declared. When using extern, the compiler will assume that this variable exists, so the compiler can continue on assuming that the variable exists. The linker will then come in, and see where that variable exists. If it does not, you get an undefined reference error. To fix this, you need to define the variables somewhere.
For example, in say resources.cpp, you would have:
#include "../headers/resources.h"
sf::Sprite PlayerSpriter::sp1;
sf::Sprite PlayerSpriter::sp2;
sf::Sprite PlayerSpriter::sp3;
// etc...
void Resources::loadResources() {
// …
}
This is in addition to what you already have in your header.
NOTE: From your edit, this would occur outside any function.

Related

I am getting an error of redefinition while using extern header file

I am getting an error of redefinition while using extern, but I was also told, that extern variable should be used like this, why I am getting this error and how should I use extern in this case so it will work? (I can use this variable even if I don't specify it in Tab.cpp, but I am getting error of finding one or more symbols, which was defined 2 times.)
Files:
Tab.h:
#pragma once
#include "wx/wx.h"
class Tab : public wxFrame {
wxDECLARE_EVENT_TABLE();
void close(wxCommandEvent& evt);
void init();
public:
Tab();
};
Tab.cpp:
#include "Tab.h"
#include "ids.h"
#include "wx/wx.h"
int maxid;
wxBEGIN_EVENT_TABLE(Tab, wxFrame)
EVT_BUTTON(2, Tab::close)
wxEND_EVENT_TABLE()
Tab::Tab() : wxFrame(nullptr, maxid++, "ERIS 2") {
init();
}
void Tab::close(wxCommandEvent &evt) { this->Close(); evt.Skip(); }
void Tab::init() {
wxGridSizer* sizer = new wxGridSizer(10, 10, 0, 0);
for(int x = 0; x < 10; ++x)
for(int y = 0; y < 10; ++y) {
sizer->Add(new wxButton(this, maxid, _(std::to_string(maxid))), wxEXPAND | wxALL);
++maxid;
}
this->SetSizer(sizer);
sizer->Layout();
}
ids.cpp:
#include "ids.h"
std::vector<Object> ids;
Object& search(const char* name) {
for(std::vector<Object>::iterator it = ids.begin(); it != ids.end(); *++it)
if((*it).name == name)
return *it;
}
Object& search(int id) {
for(std::vector<Object>::iterator it = ids.begin(); it != ids.end(); *++it)
if((*it).id == id)
return *it;
}
void add(Object& obj) {
ids.emplace_back(obj);
}
ids.h:
#pragma once
#include <vector>
#include "wx/wx.h"
struct Object {
wxObject* obj;
const char* name;
int id;
};
Object& search(const char*);
Object& search(int);
void add(Object&);
extern std::vector<Object> ids;
extern int maxid = 0;
The line
extern int maxid = 0;
in the file ids.h is a definition, because it also initializes the variable. Instead, it should only contain a declaration:
extern int maxid;
The definition should be in a source file (.cpp), not a header file (.h). Header files should only contain declarations of variables, not definitions. Otherwise, you will violate the one definition rule if you include the header file more than once, or if you already have a definition in a source file.
In your case, you already have a definition of the variable in the file Tab.cpp. The line int maxid; is a definition, because it is not using the extern keyword. If you want to initialize the variable, you should do it in that file.
There are definitions and declarations. A declaration tells the compiler that something exists. A definition is a declaration that has all the information needed to describe that thing.
For global variables like maxid, The extern says that it will have external linkage; that is, be known to the linker and be seen between different source files (translation units).
Many different translation units can say extern int maxid; and they all just say "OK, I know about this symbol, I'll find it somewhere eventually.". So, that's fine to put in a header which becomes part of more than one translation unit.
However, when you give it an initializer, in this case the =0 (one of several possible ways describe initialization), then it becomes a definition. It causes storage to be allocated and a definite location set up for that variable. You should not do that in a header, because each file that includes it will define the same variable. Thus, at link time you get more than one, which is an error.
The legacy way of doing this is to put extern int x; in the header so that everyone knows x exists, and then put int x = 0; in one CPP file so that this variable lives somewhere. Writing extern int x = 0; would mean the same thing but is un-idiomatic.
The modern way to handle this is to use a feature created for this express purpose. Put inline int x = 0; in the header file. This will define it in every translation unit that includes it, but they will be marked such that the linker understands that they are all the same and it should just pick one and ignore the others.
extern int maxid = 0; When you assign something, this is a definition and extern becomes meanless and ignored. Remove the assignment:
extern int maxid;
You have the definition in Tab.cpp and it's assigned to zero by default as a global variable.

"expected class name before '{' token" and "invalid use of incomplete type 'class CentralClass'" [duplicate]

This question already has answers here:
Resolve build errors due to circular dependency amongst classes
(12 answers)
Closed 6 years ago.
I am rewriting the mouse input tutorial on lazyfoo.net to use headers and cpp files instead of putting everything in one cpp file. I am doing this just for practice. I am running Windows 10 and I am using Code::Blocks 16.01 on a Dell laptop.
When I compile the following source code I get an error message that says "expected class name before '{' token" in my ltexture.h file. I have tried forward declaring CentralClass in my ltexture.h file and when I do that I get an error message that says "invalid use of incomplete type 'class CentralClass'". I have also looked up several answers to this same question on this website but nothing seems to work.
Here is the code.
ltexture.h
#ifndef LTEXTURE_H_INCLUDED
#define LTEXTURE_H_INCLUDED
#include <string>
#include "central_class.h"
class LTexture : public CentralClass
{
// The actual hardware texture
SDL_Texture *mTexture;
// Image dimensions
int mWidth;
int mHeight;
public:
// Initialize variables
LTexture();
// Deallocates memory
~LTexture();
// Loads image at specified path
bool loadFromFile(std::string path);
// Deallocates texture
void free();
// Renders texture at given point
void render(int x, int y, SDL_Rect *clip = nullptr, double angle = 0, SDL_Point *center = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
// Gets image dimensions
int getWidth() {return mWidth;}
int getHeight() {return mHeight;}
};
#endif // LTEXTURE_H_INCLUDED
central_class.h
#ifndef CENTRAL_CLASS_H_INCLUDED
#define CENTRAL_CLASS_H_INCLUDED
#include <SDL.h>
#include "lButtonSprite.h"
#include "lbutton.h"
#include "ltexture.h"
#include "global.h"
class CentralClass
{
// The window we'll be rendering to
SDL_Window *mWindow;
// Button objects
LButton mButtons[global::TOTAL_BUTTONS];
protected:
// The window renderer
SDL_Renderer *mRenderer;
// Mouse button sprites
SDL_Rect mSpriteClips[button::TOTAL];
LTexture mButtonSpriteSheetTexture;
public:
// Call all functions
CentralClass();
// Starts up SDL and creates window
bool init();
// Loads media
bool loadMedia();
// Main part of the program
void mainLoop();
// Frees media and shuts down SDL
void close();
// Clean up
~CentralClass();
};
#endif // CENTRAL_CLASS_H_INCLUDED
Both of these classes depend on eachother. Please help get rid of these errors. I don't know what to do.enter code here
Both files include the other one, which would result in an indefinite loop (this is prohibited by the #define).
Either way, one of them misses the class definition of the other one. The only way to resolve that is a forward declaration.
To fix it, enter class xxx; in either (or both) files, referring to respectively the other class.
In addition, there is a logical error in the structure, as class 1 contains an object of class 2, and class 2 is derived from class 1 (so it contains an object of class 1). Obviously, a class cannot contain an object of itself; that would be infinite recursive definition. I assume the class inside the other is supposed to be a pointer to an object, not an object.

C++ Include guards

I know this been asked a number of times but no answers seem to solve this.
I have two files.
Main.cpp
#include <irrlicht\irrlicht.h>
#include <vector>
#include <string>
#include <iostream>
#include "Scene.h"
#include "Camera.h"
#include "Gui.h"
irr::IrrlichtDevice* device;
irr::video::IVideoDriver* driver;
int main() {
device = irr::createDevice(irr::video::EDT_SOFTWARE, irr::core::dimension2d<irr::u32>(640, 480), 16, false, false, false, 0);
if (!device)
return 1;
device->setWindowCaption(L"NeoTrap");
driver = device->getVideoDriver();
sceneManager = device->getSceneManager();
GUIEnvironment = device->getGUIEnvironment();
//Testing
Mesh* ground = new Mesh();
//Testing
while (device->run()) {
driver->beginScene(true, true, irr::video::SColor(255, 120, 102, 136));
sceneManager->drawAll();
GUIEnvironment->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
Scene.h
#ifndef _SCENE_HEADER_
#define _SCENE_HEADER_
irr::scene::ISceneManager* sceneManager;
struct Mesh {
public:
Mesh();
private:
};
class Scene {
public:
Scene();
private:
};
#endif
What I am trying to do is declared a variable in Scene.h and define it from within the main function. I am not sure if I don't understand include guards, but I am getting weird errors:
'irr': is not a class or namespace name
syntax error: missing ';' before '*'
missing type specifier - int assumed. Note: C++ does not support default-int
but when I move the following line back in the Main.cpp file
irr::scene::ISceneManager* sceneManager;
the program compile. When am I not able to declare it in scene.h and set the value from the main function?
It's best to not declare variables in headers. It ends badly far more often than not because every file that includes the header will make their very own sceneManager. When the linker comes along to put the program together it may find dozens of sceneManagers all with an equal claim to being the real sceneManager, throw its hands up in disgust, and spray error messages all over the console.
In scene.h add
#include <irrlicht\irrlicht.h>
up at the top to declare all the bits and bobs of irrlicht so that they are available in scene.h.
Then change
irr::scene::ISceneManager* sceneManager;
to
extern irr::scene::ISceneManager* sceneManager;
extern tells the compiler that sceneManager exists and storage will be allocated somewhere else. The compiler smiles and carries on, leaving sorting out where the one, true sceneManager is to the linker.
Finally, put
irr::scene::ISceneManager* sceneManager;
in Main.cpp to allocate storage so that the linker has a sceneManager to find.
Documentation on extern
Recomended reading: When to use extern in C++
You are declaring that sceneManager is of type irr::scene::ISceneManager*, but the irr namespace doesn't exist when you are declaring that variable. Add an include to the header file that declares that namespace before declaring your variable.
After that, you'll need to declare sceneManager to be extern in the header so that each compilation unit that includes that header doesn't create its own instance of the variable. Then because it is extern, you will also want to redeclare it (without extern) in main.cpp.

When declaring a variable: variable not declared in this scope

I have the code: loading* loadingScreen = new loading(device);
When I compile the program, the compiler complains that loading screen wasn't declared:
error: 'loadingScreen' was not declared in this scope
loading* loadingScreen = new loading(device);
^
I'm unsure what's causing this. What I've tried:
Rewriting it so that the constructor isn't run.
Relocating the declaration to a different section of code.
Making sure my classes are included correctly.
Here's my main.cpp file:
#include <iostream>
#include <irrlicht.h>
#include <future> // std::async, std::future
#include <chrono> // Millisecond timer
#include <pthread.h>
#include <loading.h>
#include <fps.h>
bool loading = false;
struct load_struct {
irr::IrrlichtDevice *device;
fps *fpsLevel;
};
void load(void * loadingStruct)
{
loading = true;
struct load_struct *args = (struct load_struct *) loadingStruct;
loading = false;
pthread_exit(NULL);
}
int main()
{
//Create display to optimal settings.
irr::IrrlichtDevice *device = irr::createDevice(irr::video::EDT_NULL);
irr::s32 depth = device->getVideoModeList()->getDesktopDepth();
irr::core::dimension2d<irr::u32> resolution = device->getVideoModeList()->getDesktopResolution();
device->drop();
device = irr::createDevice(irr::video::EDT_OPENGL, resolution, depth, true, true, true, NULL); // TODO: Change last parameter
if(device==NULL)
{
std::cout << "Unable to create device! Do you have graphics drivers installed?" << std::endl;
return 1;
}
//Open data files
device->getFileSystem()->addFileArchive("Resources",true,true,irr::io::EFAT_ZIP);
device->getFileSystem()->addFileArchive("Video.tar");
device->getFileSystem()->addFileArchive("Textures.tar");
device->getFileSystem()->addFileArchive("Models.tar");
device->getFileSystem()->addFileArchive("Audio.tar");
//Load first room.
loading* loadingScreen = new loading(device);
fps *fpsLevel = new fps();
pthread_t creationThread;
struct load_struct loadingStruct;
loadingStruct.device = device;
loadingStruct.fpsLevel = fpsLevel;
//pthread_create(creationThread,NULL,load,(void *)&loadingStruct); Fix me!
while(loading==false)
{
loadingScreen->update();
std::this_thread::sleep_for(std::chrono::milliseconds(1000/60));
}
loadingScreen->kill();
// Run first room.
fpsLevel->run();
//Clean up.
device->drop();
return 0;
}
Here's my loading.h file:
#include <irrlicht.h>
#include <string>
#ifndef LOADING_H
#define LOADING_H
class loading
{
public:
loading(irr::IrrlichtDevice *device);
void update();
void kill();
protected:
int slide;
static const int SLIDES_AMOUNT = 60;
const std::string FILENAME_TEMPLATE = "Loading_Screen/%.png";
irr::video::ITexture* slides[SLIDES_AMOUNT];
};
#endif // LOADING_H
Any help would be appreciated!
The problem might be caused by the fact that you've got two different things called loading:
First, there's your class loading. But then, there's also the variable bool loading. So when you do:
loading* loadingScreen = new loading(device);
the compiler is confronted with an ambiguity and seems to prefer the variable loading over the type loading (I'm not an C++ pro and can't explain why this is the case; my guess is it's because the variable is the most "recent" definition of that name).
The fix is pretty easy: make the two names different. Since C++ is case-sensitive you should adopt the convention of starting class names with an uppercase letter: make that class Loading and Loading* loadingScreen = new Loading(device);.

Object accessing the object that contains it in C++

I'm trying to create a game in C++.
It has a "Session" class that kind of manages everything. It contains things like a GraphicsManager, a SoundManager, and the current world. It also contains a static pointer to an instance of itself. This way, I want the world to be available for the GraphicsManager so it can be rendered, for example.
Here is a simplified version of my code:
main.ccp
#pragma once
#include "Session.h"
int main() {
Session::getSession()->run(); //Starts a new session and runs it
return 0;
}
Session.h
#pragma once
#include "GraphicsManager.h"
#include "World.h"
class Session; //Forward declaration so it can have a pointer to itself
class Session {
private:
Session();
static Session* s;
World* w; //Pointer because no world is loaded at the beginning of the program
GraphicsManager gm; //Required right away
public:
~Session();
void run(); //Actually launches the game after preparation; not further declared in this example
World* getWorld(); //Returns the pointer to the current world
static Session* getSession();
}
Session.cpp
#include "Session.h"
Session::Session(): gm(GraphicsManager()) {}
Session* Session::getSession() { //Return an instance of Session. If no instance exist yet, create one.
if(s == NULL) s = new Session();
return s;
}
World* Session::getWorld() {return w;} //Returns a pointer to the current world
GraphicsManager.h
#pragma once;
class GraphicsManager {
private:
void render();
public:
void run(); //Calls the render method repeatedly; no further declaration in this example
}
GraphicsManager.cpp
#include "GraphicsManager.h"
void GraphicsManger::render() {
World* w = Session::getSession()->getWorld(); //Get pointer to current world so it can be rendered
}
The render method is where I'm stuck. If I put #include "Session.h" into the GraphicsManager.h file, it gives me an error because apparently two header files cannot include each other. If I put a forward declaration at the beginning of GraphicsManager.h or GraphicsManager.cpp, Visual Studio tells me that incomplete types are not permitted.
This has been giving me a headache for weeks. I've made games in Java before and there this pattern was accepted. So how can I do this? If this structure is not possible in C++, do you have other suggestions for it?
In GraphicsManager.cpp, the compiler needs to know about the Session, so you have to #include "Session.h" which by the way includes GraphicsManager as well as World.
A forward definition will not be sufficient, as the compiler would not be able to check types of getSession()->getWorld() expression.
Apparently your GraphicsManager.h doesn't rely itself on the other definitions, so there should'nt be an issue here.
Try to include Session.h to GraphicsManager.cpp:
#include "Session.h"
void GraphicsManger::render() {
World* w = Session::getSession()->getWorld(); //Get pointer to current world so it can be rendered
}
This way Session class defenition will be visible for compiler in GraphicsManager.cpp, so it will not generate incomplite type error. On the other hand, Session.h is not included to GraphicsManager header, so there will no problem that both headers include each other.