0

I am working on a little game engine but I got stuck at something. Explanation : I have two classes, cEntity And ObjectFactory :

cEntity

class cEntity:public cEntityProperty
{
    Vector2 position;
    Vector2 scale;
  public:
   cEntity(void);
   cEntity(const cEntity&);
   ~cEntity(void);
  public:
   void init();
   void render();
   void update();
   void release();
};

ObjectFactory

#include "cEntity.h"
#include <vector>

class ObjectFactory
{
   static std::vector<cEntity> *entityList;
   static int i, j;
  public:
   static void addEntity(cEntity entity) {
   entityList->push_back(entity);
}
  private:
   ObjectFactory(void);
   ~ObjectFactory(void);
};

std::vector<cEntity> *ObjectFactory::entityList = new std::vector<cEntity>();

Now I am adding new cEnity to ObjectFactory in cEntity constructor but facing an error related to circular references: for using ObjectFactor::addEntity() I need to define the ObjectFactory.h in cEntity class but it creates a circular reference.

kebs
  • 6,387
  • 4
  • 41
  • 70
Ravi
  • 95
  • 1
  • 3
  • 10
  • Would be helpful to see more of your class definition to see where it's going wrong. This may be of use to you: http://stackoverflow.com/questions/5120768/how-to-implement-the-factory-pattern-in-c-correctly – Jon Cage May 07 '14 at 13:54
  • include guards should do the trick – sp2danny May 07 '14 at 13:58
  • My eyes burn... using `new` with a `vector`... why? – Mgetz May 07 '14 at 14:13
  • You might reconsider your design? Why not create the Entity using the Factory, like the actual design pattern would propose? So the Factory would also be able to keep track of all instances... Without circular dependencies ofc. – Sambuca May 07 '14 at 14:15
  • The entity shouldn't need to know about the factory that is creating it, and the factory's API shouldn't necessarily need to publish the concrete entity it is creating. For testing purposes, among other things, the factory should typically return an object that can do X. – ssube May 07 '14 at 14:19

1 Answers1

1

I think your code might have an underlying architectural issue given how you have described the problem.

Your ObjectFactory should be handling the cEntities, which in turn should be unaware of the "level above". From the description of the problem you are having, it implies that you're not sure what class is in charge of what job.

Your cEntitys should expose an interface (i.e. all the stuff marked "public" in a class) that other bits of code interact with. Your ObjectFactory (which is a bit badly named if doing this job, but whatever) should in turn use that interface. The cEntitys shouldn't care who is using the interface: they have one job to do, and they do it. The ObjectFactory should have one job to do that requires it to keep a list of cEntitys around. You don't edit std::string when you use it elsewhere: why is your class any different?


That being said, there's two parts to resolving circular dependencies (beyond "Don't create code that has circular dependencies in the first place" - see the first part to this answer. That's the best way to avoid this sort of problem in my opinion)

1) Include guards. Do something like this to each header (.h) file:

#ifndef CENTITY_H
#define CENTITY_H
class cEntity:public cEntityProperty
{
Vector2 position;
Vector2 scale;
public:
cEntity(void);
cEntity(const cEntity&);
~cEntity(void);
public:
void init();
void render();
void update();
void release();
};
#endif

What this does:

  • The first time your file is included, CENTITY_H is not defined. The ifndef macro is thus true, and moves to the next line (defining CENTITY_H), before it moves onto the rest of your header.
  • The second time (and all future times), CENTITY_H is defined, so the ifndef macro skips straight to the endif, skipping your header. Subsequently, your header code only ever ends up in your compiled program once. If you want more details, try looking up how the Linker process.

2) Forward-declaration of your classes.

If ClassA needs a member of type ClassB, and ClassB needs a member of type ClassA you have a problem: neither class knows how much memory it needs to be allocated because it's dependant on another class containing itself.

The solution is that you have a pointer to the other class. Pointers are a fixed and known size by the compiler, so we don't have a problem. We do, however, need to tell the compiler to not worry too much if it runs into a symbol (class name) that we haven't previously defined yet, so we just add class Whatever; before we start using it.

In your case, change cEntity instances to pointers, and forward-declare the class at the start. You are now able to freely use ObjectFactory in cEntity.

#include "cEntity.h"
#include <vector>

class cEntity;  // Compiler knows that we'll totally define this later, if we haven't already

class ObjectFactory
{
static std::vector<cEntity*> *entityList;  // vector of pointers
static int i, j;
public:
static void addEntity(cEntity* entity) {  
entityList->push_back(entity);
}
// Equally valid would be:
// static void addEntity(cEntity entity) {
// entityList->push_back(&entity);}
// (in both cases, you're pushing an address onto the vector.)
// Function arguments don't matter when the class is trying to work out how big it is in memory
private:
ObjectFactory(void);
~ObjectFactory(void);
};
std::vector<cEntity*> *ObjectFactory::entityList = new std::vector<cEntity*>();
KidneyChris
  • 857
  • 5
  • 12