While trying to make a simple game, I've run in to a circular dependency problem.
I searched on the internet and found that forward declaring could fix it, but... Both of my classes depend on a static value.
Is there any easy way to fix, perhaps to forward declare the static values, or do I have to rewrite the core of my game?
2ND EDIT: Looks like I was wrong, the error's still there even after removing almost everything:
main.cpp:
#include "App.h"
//Start the app
int main(int argc, char* args[]){
App App;
return App.on_execute();
}
App.h:
#ifndef APP_H
#define APP_H
#include "Object.h"
class App
{
public:
//Runs when the program starts
int on_execute();
};
#endif // APP_H
App.cpp:
#include "App.h"
int App::on_execute(){
return 0;
}
Object.h:
#ifndef OBJECT_H
#define OBJECT_H
#include <string>
#include <vector>
#include <stdio.h>
#include <SDL.h>
#include <math.h>
#include "Entity.h"
class Object
{
public:
Object(int character, int x, int y, std::string name, SDL_Color color, bool blocks);
//Object vector
static std::vector<Object*> objects;
};
#endif // OBJECT_H
Object.cpp:
#include "Object.h"
std::vector<Object*> Object::objects;
Object::Object(int character, int x, int y, std::string name, SDL_Color color, bool blocks){
}
Entity.h:
#ifndef ENTITY_H
#define ENTITY_H
#include "Object.h"
#include <sdl.h>
class Entity : public Object
{
public:
Entity(int character, int x, int y, std::string name, SDL_Color color, bool blocks, int hp, int power, int defense);
};
#endif // ENTITY_H
Entity.cpp:
#include "Entity.h"
Entity::Entity(int character, int x, int y, std::string name, SDL_Color color, bool blocks, int hp, int power, int defense) : Object(character, x, y, name, color, blocks){
}
I think the design of your code may need to be reworked.
First of all, I'd really discourage you from using non-primitive, non-trivial class statics where possible, whether class static or global static. Non-trivial static classes will have an explicit constructor call before main, and will need to register a destruction to be called after main. The relative ordering of these things is undefined. Worse, if you have a library structure later such that the assembly from the same .cpp file shows up twice, weird things can happen where two copies of the object get constructed, but the same one is destroyed twice.
Second, some of the information is unclear. For example, you claim that the Map class has a static member of type Map. I really don't think this is possible; the static Map member will also have an object of type map, and so on. Similarly with the vector of Objects declared inside Object. Maybe in both these cases you mean inside the file Map.cpp or Object.cpp, as opposed to literally inside the class?
Third, be clear on what forward declaration gives you. It makes the compile aware that something exists, nothing more. It lets you have pointers and references to that type. You cannot create an object or even declare a member variable of a forward declared type, because the compiler doesn't know the size of the forward declared object. You can't use its methods because the compiler doesn't know they exist.
Fourth, you didn't talk about your header files at all. It's only a circular dependency if Map.h requires Object.h, and vice versa. Two header files can't both include each other. On the other hand, the implementation is in Map.cpp and Object.cpp, both of these files can include both Map.h and Object.h. However, personally I prefer to avoid having mutually dependent classes.
What I'd probably suggest is that a Map should own the Objects present on that map. The pattern right now with Map accessing this global is not a good one. Instead of having objects be a global, make std::vector objects a member of the Map class. Notice that if you decide to have multiple Maps later, this works much better, each Map will own the Objects located on that map. The current design doesn't work well if there's more than one Map.
You can then implement move_to as a method not of Object, but rather of Map. Map::move_to(i, dx, dy) moves the ith Object.
Related
I have this piece of code
#ifndef STATION_H
#define STATION_H
#include <vector>
#include "Dispenser.h"
#include "Cashier.h"
//class Cashier;
class Station
{
private:
int price;
int dispenser_count;
int cashier_count;
std::vector<Dispenser> dispensers;
std::vector<Cashier> cashiers;
public:
Station(int, int, int);
int GetPrice() const { return price; }
Dispenser *LookForUnoccupiedDispenser(int &id);
Dispenser *GetDispenserByID(int id);
Cashier *LookForUnoccupiedCashier();
};
#endif // STATION_H
When I have the class Cashier line commented, the compiler fails with a 'Cashier' was not declared in this scope error even though Cashier.h was included. Uncommenting it makes it possible to compile but I'm concerned that it shouldn't be happening.
Cashier.h
#ifndef CASHIER_H
#define CASHIER_H
#include "Station.h"
class Station;
class Cashier
{
private:
bool busy;
Station *at_station;
public:
Cashier(Station *employer);
bool IsBusy() const { return busy; }
};
#endif // CASHIER_H
How is it possible? It's clearly declared in the header file and as far as I know, #include does nothing more than pasting the content of a file into another one.
Thank you for the answers in advance!
Your station.h includes cachier.h. This is an example of cyclic dependency. Given that you only have a pointer to Station in Cachier I'd suggest removing the dependency of station.h and forward declare it.
An #include is literally nothing more than verbatim copy and paste of that file into the current compilation unit. The guards protect you from the effect of an infinite include cycle, but due to the guards one of the #includes does nothing, i.e. does NOT suck in the declaration (nor definition) of the respective class. This results in the error you get. In station.h the compiler has never seen any mention of the Cachier type when it sees the Station type.
I have this subclass Pirate.cpp and I want its mov function to access an array from main.
This array is basically the map (To check if it already has ship, dock and to access the array to change the object's (pirate ship) location from map[1][1] to map[1][2].
This map is a two-dimensional array of sea objects that each one can hold a ship with the pointer.
Ship is parent class of pirate (I have other subclasses I will do dynamic_cast before inserting Pirate to the Ship pointer).
I have an error code: 'Map' , 'Place' was not declared in this scope which I understand.
So basically how do I deal with this scope issue? Is there an alternate approach?
Pirate.cpp
#include "pirate.h"
#include "Sea.h"
void Pirate::mov()
{
MAP[1][2]->(*place)=MAP[1][1]->(*place)
MAP[1][2]->(*place)=NULL
}
Sea.h
#ifndef SEA.H
#define SEA.H
#include "ship.h"
class Sea
{
private:
bool hasShip;
bool isDock;
protected:
Ship *place = NULL;
public:
bool gethasShip() const {return hasShip;}
bool getisDock() const {return isDock;}
void sethasShip(bool i) {hasShip = i;}
void setisDock(bool i) {isDock = i;}
};
#endif
main
#include <iostream>
#include <vector>
#include <string>
#include "Ship.h"
#include "Sea.h"
#define SIZE 100
using std::cout;
using std::vector;
extern Sea Map[SIZE][SIZE];
int main()
{
Sea Map[SIZE][SIZE];
}
extern makes a declaration instead of a definition. It only says that somewhere the object is definied.
You need to have Sea Map[SIZE][SIZE]; in your main.cpp and extern Sea Map[SIZE][SIZE]; in other files from which you access the array.
There are a couple of things you could do:
You could make the Map a global variable by declaring it outside of main(), and use extern to reach it from within Pirate::mov.
You could also create a singleton, but that suffers from some of the same problems as globals.
A better solution is a class that contains the Map and the Pirates. When you construct your Pirates you could have each Pirate a reference to the Map.
So far I've looked up most of the typical solutions for cases of this error and yet non of them seems to work with my code. I'm using dev-c++
The structure of problematic class is following.
m.hh
#ifndef M_H
#define M_H
#include "z.hh"
#include <iostream>
#include <string>
using namespace std;
class M: public Z
{ /* this line is marked by the compiler as errorneous */
void m1();
void m2();
};
#endif
m.cpp
#include <iostream>
#include <string>
#include "m.hh"
using namespace std;
void M::m1() {/*bla bla*/};
void M::m2() {/*bla bla*/};
}
EDIT:
z.hh
#ifndef Z_H
#define Z_H
#include "m.hh"
#include <iostream>
#include <string>
using namespace std;
class Z;
static Z* s(string g, string i);
#endif
z.cpp
#include "z.hh"
#include <iostream>
#include <string>
class Z
{
public:
string i;
string g;
void set_i(string im) {i = im;}
string get_i() {return i;}
string get_g() {return g;}
virtual void m1()=0;
virtual void m2()=0;
Z* s(string g, string i) {
Z * z;
if(g=="m"){
M * z = new M;
}
}
};
Thanks!
Remove #include "m.hh" from z.hh to fix the circular include.
THE PROBLEM
You cannot derive from an incomplete type, which is what Z is in m.hh.
Upon deriving from a type the compiler must know the definition of said type. Just imagine you are trying to call a derived member function from Z on an object of type M, how would the compiler know if such call is a valid construct without knowing if Z actually declares such member?
And, a more relevant point, how would M be able to initialize Z without knowing what Z is?
THE SOLUTION
Move the definition of class Z to z.hh, and leave the definitions of its member functions in z.cpp (the same way you have split up M across m.hh, and m.cpp).
Well, the z.cpp file is actually a class declaration and should be a header file. A forward decalaration is only sufficient when you deal with pointers to that class, but not for inheriting from one (the compiler does need to know z's class layout for that).
The z.hh is not really needed, and the function declaration in it is not what you think (it's not a member function declaration). You can delete it and rename z.cpp to z.hh.
Ok, the exchange with #Luchian Grigore made me realize what you probably wanted and why you had "two z.hh". Z is to produce an M, but M inherits from Z, so there is a circular dependency. In C/C++ the way to break such a circle is to limit what one of the classes needs to know from the other: In order to declare a member function s that produces a pointer to a new M Z's class declaration only needs a typename M, not a the whole class declaration. So just a forward declaration (class M;) that introduces the type name M into the declaration of Z is enough; if the pointer to the M object is returned as a pointer to the base, Z, M's name is not even needed at all when Z is declared.
The definition of the factory function (be it file static or a member function) needs, if it is to produce an M, M's complete declaration though. That would be in a seaparate cpp file, which would include a complete header with M's full declaration.
I am attempting to develop a class with a function that can take a vector of items as it's argument.
I can get it to work fine if I use a vector of type int, or other primitive, but I can't get it to work with a vector of objects.
eg:
In my header file:
int influenceParticles(vector<Particle> particles);
This is what I am after, but won't compile (error stated is "'Particle' was not declared in this scope").
The particle.h file has been included at the top of this header file.
Clarification
Here is the .h file that gives me the error
#ifndef _PARTICLE_ATTRACTOR
#define _PARTICLE_ATTRACTOR
#include "ofMain.h"
#include "particle.h"
class ParticleAttractor {
//private
public:
ParticleAttractor(int posX, int posY); //constructor (void)
int influenceParticles(vector<Particle> particles);
};
#endif
Maybe you have cyclic includes, ie. if the ParticleAttractor.h also includes the Particle.h. To solve this, you should make a forward declaration of Particle in ParticleAttractor.h:
class Particle;
You should also consider passing the vector by reference to avoid copying:
int influenceParticles(vector<Particle>& particles);
First Particle must be a defined type. This definition should work:
int influenceParticles(vector<vector<int> > particles);
For practice, it is better to use the by reference parameter type rather than by value. So it is better to define it as:
int influenceParticles(vector<vector<int> >& particles);
this is my first question here.
Writing some code, i receive this error from g++: "Entity was not declared in this scope", in this context:
#ifndef Psyco2D_GameManager_
#define Psyco2D_GameManager_
#include <vector>
#include "Entity.h"
namespace Psyco2D{
class GameManager{J
private:
std::vector<Entity> entities;
};
}
#endif
This is the content of Entity.h:
#ifndef Psyco2D_Entity_
#define Psyco2D_Entity_
#include <string>
#include "GameManager.h"
#include "EntityComponent.h"
namespace Psyco2D{
class Entity{
friend class GameManager;
private:
/* Identificatore */
std::string _name;
/* Components list */
std::map<const std::string, EntityComponent*> components;
protected:
Entity(const std::string name);
public:
inline const std::string getName() const{
return this->_name;
}
void addComponent(EntityComponent* component, const std::string name);
EntityComponent* lookupComponent(const std::string name) const;
void deleteComponent(const std::string name);
};
}
#endif
If i use std::vector<class Entity> instead of std::vector<Entity> it works.
Why?
Thanks to all =)
The problem is you have a cyclic dependency. Take out #include "GameManager.h" in Entity.h, since you don't actually need it in that header. (Up-vote this answer, which first pointed it out.)
Note the guards are actually the problem; but don't take them out! You just need to minimize the includes you have, and declare (and not define) types when possible. Consider what happens when you include Entity.h: As some point it includes GameManager.h, which in turn includes Entity.h. At this point, Entity.h already has its header guard defined, so it skips the contents. Then the parsing of GameManager.h continues, where upon it runs into Entity, and rightfully complains it is not defined. (Indeed, this is still the process of including GameManager.h in the first inclusion of Entity.h, far before Entity is defined!)
Note your numerous edits demonstrate why it's important to post real code, not re-synthesized code. You need real details to get real answers.
Old:
Entity is in the Psyco2D namespace. You need to specify that:
class GameManager{
private:
std::vector<Psyco2D::Entity> entities;
};
Assuming the first snippet is part of GameManager.h you have a circular header dependency. I believe you can fix this by changing the GameManager.h include in Entity.h to class GameManager; instead.
Additionally as GMan noted, Entity is in a namespace and you need to qualify Entity with the namespace name.
Remove the Psyco2D-namespace and it will work without declaring "class Entity".