Forward declaration & circular dependency

2020-02-09 11:34发布

问题:

I've got two classes, Entity and Level. Both need to access methods of one another. Therefore, using #include, the issue of circular dependencies arises. Therefore to avoid this, I attempted to forward declare Level in Entity.h:

class Level { };

However, as Entity needs access to methods in Level, it cannot access such methods, since it does not know they exist. Is there a way to resolve this without re-declaring the majority of Level in Entity?

回答1:

A proper forward declaration is simply:

class Level;

Note the lack of curly braces. This tells the compiler that there's a class named Level, but nothing about the contents of it. You can then use pointers (Level *) and references (Level &) to this undefined class freely.

Note that you cannot directly instantiate Level since the compiler needs to know the class's size to create variables.

class Level;

class Entity
{
    Level &level;  // legal
    Level level;   // illegal
};

To be able to use Level in Entity's methods, you should ideally define Level's methods in a separate .cpp file and only declare them in the header. Separating declarations from definitions is a C++ best practice.

// entity.h

class Level;

class Entity
{
    void changeLevel(Level &);
};


// entity.cpp

#include "level.h"
#include "entity.h"

void Entity::changeLevel(Level &level)
{
    level.loadEntity(*this);
}


回答2:

you two options:

  1. use pointers in which case your forward declares should be ok.
  2. inline the methods of one class, in which case if you include the .h file you can use the methods of the other.

Personally I would go down path number 1, it's cleaner and allows better access. I use a lot of shared_ptr so I do not have to worry about deletes...

Entity.h:
class Level;
class Entity {

private:
   Level* m_pLevel;

public:
   bool  CheckLevel ();
   bool WasItThere();


Level.h

class Entity;
class Level {

private:
   Entity* m_pEntity;



    public:
       public bool CheckMyStuff();
       public bool CheckItOut() { return m_pEntity->WasItThere();}
}


Entity.cpp

#include "Level.h"

bool Entity::CheckLevel () {
  return true;
}


bool Entity::CheckLevel() {
   return m_pLevel->CheckMyStuff();
}

bool Entity::WasItThere() {
   return true;
}



Level.cpp

bool Level::CheckMyStuff() { 
    return true;
}

bool Level::CheckItOut() { 
    return m_pEntity->WasItThere();
}