472,983 Members | 2,102 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,983 software developers and data experts.

circular include

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
6 7519
Banfa
9,065 Expert Mod 8TB
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
Jordi
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
9,065 Expert Mod 8TB
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
Jordi
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
Jordi
9
Never mind, the new problem was similar to the old one, I just didn't see it.
Feb 26 '07 #6
Banfa
9,065 Expert Mod 8TB
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

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

Similar topics

1
by: Mohit Gupta | last post by:
Hi all, I have just started working on VC++ .Net and have problem with circular dependencies of 2 files. I created 2 forms "Form1" and "Form2", which respectively created 2 .h files, Form1.h...
3
by: crichmon | last post by:
Any general advice for dealing with circular dependencies? For example, I have a situation which, when simplified, is similar to: ///////////// // A.h class A { public: int x;
6
by: Markus Dehmann | last post by:
I have a circular dependency between two classes. The FAQ hint about a forward declaration does not help in my case ( How can I create two classes that both know about each other?) Error:...
16
by: Kiuhnm | last post by:
Is there an elegant way to deal with semi-circular definitions? Semi-circular definition: A { B }; B { *A }; Circular reference: A { *B }; B { *A }; The problems arise when there are more...
4
by: ro86 | last post by:
Hello everyone! I am a newbie to C++ (~1 Week experience) and I have a few months of experience with object-oriented languages (Objective-C). I am currently working just for fun on a particle...
3
by: JCB | last post by:
Hi, I have two C file which are referencing in a circular way. To simplify I use an example with car : Suppose I have a program for cars. I have car.c, structure car and functions...
1
by: Booser | last post by:
// Merge sort using circular linked list // By Jason Hall <booser108@yahoo.com> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> //#define debug
6
by: T Koster | last post by:
After a few years of programming C, I had come to believe that I finally knew how to correctly organise my structure definitions in header files for mutually dependent structures, but I find myself...
5
by: fomas87 | last post by:
Hi guys, I'm writing a framework for an sdl gui in c++, but got stuck on the circular dependency, I've read a lot of articles about resolving dependencies and about forward declaration but none of...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
3
by: nia12 | last post by:
Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
4
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.