By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,234 Members | 1,896 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,234 IT Pros & Developers. It's quick & easy.

circular include

P: 9
I'm having a problem which I think has to do with the circular use of inlcuding header files.
The short version of my code would look a bit like this, I think:
GameEngine.h:
Expand|Select|Wrap|Line Numbers
  1. #ifndef GAME_ENGINE
  2. #define GAME_ENGINE
  3.  
  4. #include "Player.h"
  5.  
  6. class GameEngine
  7. {
  8. public:
  9.     GameEngine ();
  10. // ..
  11.  
  12. private:
  13.     // ..
  14.     Player* players[2];
  15. };
  16.  
  17. #endif
  18.  
Player.h:
Expand|Select|Wrap|Line Numbers
  1. #ifndef PLAYER
  2. #define PLAYER
  3.  
  4. #include "GameEngine.h"
  5.  
  6. // This class contains pure virtual functions!
  7. class Player
  8. {
  9. public:
  10.     // ..
  11. protected: 
  12. //..
  13. private:
  14.     GameEngine* game; // line 37
  15. // ..
  16. };
  17.  
  18. #endif
  19.  
These are the errors I'm getting:
Player.h:37: error: ISO C++ forbids declaration of `GameEngine' with no type
Player.h:37: error: expected `;' before '*' token

If I change line 37 into GameEngine Game; (so it's not a pointer anymore), the error changes to:
Player.h:37: error: `GameEngine' does not name a type

If I remove line 37, a lot more errors are found:
Players\RandomPlayer.cpp:12: error: expected class-name before '{' token
Players\RandomPlayer.cpp:19: error: expected `,' or `...' before "note"
Players\RandomPlayer.cpp:19: error: ISO C++ forbids declaration of `Notification' with no type
Players\RandomPlayer.cpp:28: error: class `RandomPlayer' does not have any field named `Player'
Players\RandomPlayer.cpp:34: error: `name' undeclared (first use this function)
Players\RandomPlayer.cpp:34: error: (Each undeclared identifier is reported only once for each function it appears in.)
GameEngine.h:19: error: `Player' has not been declared
GameEngine.h:19: error: ISO C++ forbids declaration of `parameter' with no type
GameEngine.h:30: error: ISO C++ forbids declaration of `Player' with no type
GameEngine.h:30: error: expected `;' before '*' token
Player.cpp:38: warning: unused variable 'move'
:: === Build finished: 10 errors, 1 warnings ===

All of these errors seem to have to do with types like Player and GameEngine not being known. Does anybody have any idea how I can repair this?

Complete header files: (there are of course more files, so if it is necessary to see those to, just ask for them)

GameEngine.h:
Expand|Select|Wrap|Line Numbers
  1. #ifndef GAME_ENGINE
  2. #define GAME_ENGINE
  3.  
  4. #include <vector>
  5.  
  6. #include "Board.h"
  7. #include "Player.h"
  8. #include "Players.h"
  9.  
  10. class GameEngine
  11. {
  12. public:
  13.     GameEngine ();
  14.     GameEngine (std::vector<CellOwner>);
  15.  
  16.     Board* getBoard () const;
  17.     int getTurns () const;
  18.     bool end () const;
  19.     bool setPlayer (const CellOwner, Player*);
  20.     bool removePlayer (const CellOwner);
  21.     void swapPlayers ();
  22.     void restart ();
  23.     void next ();
  24.     bool undo ();
  25.     bool redo ();
  26.  
  27. private:
  28.     unsigned int turn;
  29.     Board* board;
  30.     Player* players[2];
  31.  
  32.     std::vector<unsigned int> moves;
  33. };
  34.  
  35. #endif
  36.  
Player.h:
Expand|Select|Wrap|Line Numbers
  1. #ifndef PLAYER
  2. #define PLAYER
  3.  
  4. #include <string>
  5. #include <list>
  6.  
  7. #include "GameEngine.h"
  8. #include "Board.h"
  9.  
  10.  
  11. enum Notification { CLEAR };
  12.  
  13. class Player
  14. {
  15. public:
  16.     virtual ~Player();
  17.  
  18.     void addObserver (Player* observer);
  19.     void removeObserver (Player* observer);
  20.     void makeMove (const Board*);
  21.     std::string getName () const;
  22.     bool canLearn () const;
  23.     bool isHuman () const;
  24.  
  25.     virtual void setName (const std::string name) = 0;
  26.     virtual void learn (const Board*, const int) = 0;
  27.     virtual void notify (const Notification) = 0;
  28.     virtual int thinkMove (const Board*) = 0;
  29.     virtual void giveTurn () = 0;
  30. protected: // Protected, because observers can be asked for help
  31.     std::list<Player*> observers;
  32.     std::string name;
  33.     bool turn;
  34.  
  35.     Player (const bool, const bool);
  36. private:
  37.     GameEngine* game;
  38.     const bool human;
  39.     const bool teachable;
  40. };
  41.  
  42. #endif
  43.  
  44.  
Thanks for any help!
Feb 23 '07 #1
Share this Question
Share on Google+
6 Replies


Banfa
Expert Mod 5K+
P: 8,916
I'm having a problem which I think has to do with the circular use of inlcuding header files.
Correct!

The problem is GameEngine.h includes Player.h but has (correctly) set an double include protection symbol so when Player.h tries to include GameEngine.h it gets an empty file because of this double include protection. Then class Player tries to use class GameEngine, however because the copy of GameEngine.h that Player.h included was empty the class GameEngine has not been defined and you get all the errors.

However all is not lost. If you look at class GameEngine you will see it only uses class Player in the context of a pointer to Player (i.e. doesn't try to access any members) and in fact class Player only uses class gameEngine in the context of a pointer to GameEngine. In this case the compiler only needs to reserve space for a pointer so it only needs to know that the class exists not what it's details are.

There is a way to inform a the compiler that a class exists (or will exist) but define any of it's details, it is called "forward declaring the class (or structure)" and the syntax is

Expand|Select|Wrap|Line Numbers
  1. class GameEngine;
  2.  
You can remove the inclusion of the headers and forward declare your classes instead, in GameEngine.h this looks like

Expand|Select|Wrap|Line Numbers
  1. #ifndef GAME_ENGINE
  2. #define GAME_ENGINE
  3.  
  4. class Player.h;
  5.  
  6. class GameEngine
  7. {
  8. public:
  9.     GameEngine ();
  10. // ..
  11.  
  12. private:
  13.     // ..
  14.     Player* players[2];
  15. };
  16.  
  17. #endif
  18.  
Feb 23 '07 #2

P: 9
Thank you very much for you quick reply! I had figured parts of what you said out, but your explanation was very good and I understand a lot better now.

I'm assuming though that you meant to write "class Player;" instead of "class Player.h;".

This deals with my problem very well, but now I have another (far less important question):
From your explanation, I gather that I can always use forward declaration in header files where I'm only using a pointer to an object. I would still need to include the header files in the *.cpp files (because I'll be using methods of the forward declared class), so I might as well do it in a header file. However, it isn't strictly necessary there since a forward declaration would do. So, what would be considered good practice?
Feb 23 '07 #3

Banfa
Expert Mod 5K+
P: 8,916
I'm assuming though that you meant to write "class Player;" instead of "class Player.h;".
Err, yes I did.

From your explanation, I gather that I can always use forward declaration in header files where I'm only using a pointer to an object. I would still need to include the header files in the *.cpp files (because I'll be using methods of the forward declared class), so I might as well do it in a header file. However, it isn't strictly necessary there since a forward declaration would do. So, what would be considered good practice?
This sort of thing is a lot down to personal choice.

For instance in some companies #including from header files at all is frowned upon and you tend to have long lists of headers in you c/cpp files. Personally I don't agree with this because those long lists of headers just get very unweidly and you often end up with unrequired headers in files.

Another not uncommon approach is to include all headers into another single header file in the correct order and then include that header into your c/cpp files. If you use precompiled headers this doesn't have too much effect of compile time. I don't like this approach because it is a bit of a sledge hammer approach.

So I say if a header requires another header then include it, however try not to let the header inclusion go too deep, not more than 1 or 2 levels.

As to forward declaration it is required to get round the problem you have had but I don't think it is very elegant so my opinion is that you should arrange your header inclusion to reduce the amount of required forward declaration to a minimum.

However note this is all opinion, I have not seen many "best practices" covering the topic of forward declaration.
Feb 23 '07 #4

P: 9
Thanks again for your reply!

The solution worked for a while. I forward declared GameEngine in Player.h and then included it in Player.cpp, where I could use all of GameEngine's public methods. However, I now derived a class from Player and put it in a file called RandomPlayer.cpp. I've created no header file for this, because this class is really basic and the public interface is almost exactly the same as Player's. However, Including both Player.h and GameEngine.h in RandomPlayer.cpp gives me this errors:
E:\Jordi\Development\Projects\FourFun\lib\Players\ RandomPlayer.cpp:38: error: invalid use of undefined type `struct GameEngine'
E:\Jordi\Development\Projects\FourFun\lib\Players\ ..\Player.h:10: error: forward declaration of `struct GameEngine'
:: === Build finished: 2 errors, 0 warnings ===

I have also forward declared Player in GameEngine.h, so those files are not directly linking to eachother anymore.

Does anyone know why this is and what I can do about it?
Feb 25 '07 #5

P: 9
Never mind, the new problem was similar to the old one, I just didn't see it.
Feb 26 '07 #6

Banfa
Expert Mod 5K+
P: 8,916
Never mind, the new problem was similar to the old one, I just didn't see it.
Hooray, because while I was aware of the second question I had kind of lost the thread (or was it is plot???).

Happy to know your current problems are solved.
Feb 26 '07 #7

Post your reply

Sign in to post your reply or Sign up for a free account.