You can do anything with forward declarations except have Player have a Game object and vice versa (which would create an infinite loop anyway if it were allowed -- Player.Game.Player.Game.etc)
- If Game has Player objects, then Player must be
defined (ie: has a body) first
- If Game has Player pointers, then Player can be defined first, or you can forward declare Player prior to defining Game
and vice versa:
- If Player has Game objects, then Game must be defined first
- If Player has Game pointers, then Game can be defined first, or you can forward declare Game
If you're dealing with pointers only (no objects), then it doesn't matter which is defined first as long as you forward declare.
Assuming Game has Player objects, and Player only has a Game pointer, lay it out like so:
-) seperate them so Game is in "game.h" and "game.cpp", and Player is in "player.h" and "player.cpp"
-) guard against recursive/redundant includes with #ifndef and #define (I recommend doing this with all your headers)
-) in "player.h", forward declare Game, then define Player:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
#ifndef __PLAYER_H_INCLUDED__
#define __PLAYER_H_INCLUDED__
// included dependencies for Player
// if Player needs any objects *defined* before it, #include them here
// do not include things you can forward declare
// forward declared dependencies for Player
class Game;
// and anything else Player needs
// the actual Player class
class Player
{
// stuff
Game* game; // okay! Game is forward declared
};
#endif
|
-) Since Game is forward declared in "player.h" -- do not inline anything that requires Game to be defined. Anything that actually uses Game will have to be put in "player.cpp" -- where both Game and Player will be fully defined with the right includes:
1 2 3 4 5
|
// in player.cpp
#include "player.h" // defines Player, forward declares Game
#include "game.h" // defines Game
// Player and Game now fully defined -- use at will
|
-) alternatively to the above, you can #include "game.h" after the Player class is defined in "player.h" so that you don't have to #include it in "player.cpp". However I don't recommend that approach. In fact I probably shouldn't have even mentioned it XD
-) in "game.h", #include "player.h" since Player's full definition is required to exist before Game's definition exists. If player.h is guarded with #ifndef (as in the above example) there are no ill effects to putting the #include in the header. In fact, IMO, it makes the code much more managable because you know exactly what dependencies are needed where (no need to include 5 seperate files if you make a new source file that needs Game -- you can just include "game.h" and be done with it):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
#ifndef __GAME_H_INCLUDED__
#define __GAME_H_INCLUDED__
// included dependencies for Game:
#include "player.h" // Game needs Player defined
// forward declared dependencies for Game:
// put other stuff you can forward declare here
class Game
{
// stuff
Player thePlayer; // okay! Player is fully defined
};
#endif
|
As to whether or not it's the best design decision to have Player and Game communicate back and forth like this -- that's another topic =P. But this should work just fine if that's how you want to go.
EDIT-- forgot an #endif
Also -- what I suspect might be your problem is you're inlining function bodies in the class definition. This is fine
as long as objects you use are fully defined. Since Player does not have Game fully defined... you can't inline functions in the class which use Game.
To elaborate further:
1 2 3 4 5 6 7 8 9 10 11 12
|
// in player.h
class Player
{
public:
void SomeFunction()
{
game->DoSomething(); // Error! game not fully defined. Can't inline this function
}
protected:
Game* game;
};
|
Do this instead:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
// in player.h
class Player
{
public:
void SomeFunction();
protected:
Game* game;
};
//-----------------------------------
//-----------------------------------
// in player.cpp
#include "player.h"
#include "game.h"
void Player::SomeFunction()
{
game->DoSomething(); // okay! Game is fully defined
}
|
* disclaimer. I'm using the term "inline" here as 'implicitly inlining' (ie: defining the function in the class itself). It is still possible to inline functions which use not-yet-fully-defined classes, but that's another topic.