Compiling problem when including a class in another class

Started by
9 comments, last by ninmonkeys 17 years, 9 months ago
I'm having a compiling error when I'm trying to use a class as a member of another class. I've been looking at the gamedev article Organizing Code Files in C and C++' but I'm still stuck. The classes are: Game() is a class that controls the game. Actor() is the base class that all actor's derive from. Unit() is a base class unit class that derives from Actor() UnitManager() manages a list of Unit()'s The source files are Right now Unit.h/cpp includes/implements Actor() and Unit(). UnitManager is in UnitManager.h/cpp Game.h/cpp is mostly empty, I'm trying to add a UnitManager object to it. I'm trying to use a UnitManager() variable in the Game() class. I don't think it's a namespace issue, because I tried with and without the namespace and it is the same error. I also tried using a Unit() class in place of the UnitManager() but that also ends up as the same error. This is the line that is a problem:
UnitManager m_unitManager;




Which gives:
Game.h:53: error: field `m_unitManager' has incomplete type.
I think that means it sees that UnitManager is a class, but not the implementation. If I try without the 'forward include' (I think it's called? Using 'class UnitManager;' in Game.h ) I get:
Game.h:48: error: using-declaration for non-member at class scope
I didn't include the .cpp files because I thought it wasn't neccessary. Do you need to know or see anything else? Game.h
[source lang="cpp]//Game.h

#ifndef RTS_GAME_H
#define RTS_GAME_H

// About: Class that controls everything

//standard
//#include <iostream>

#include "globals.h"
#include "Actor.h"
#include "UnitManager.h"

namespace rts {

class UnitManager; //forward include, unsure if I need this.

class Game
{
	public:
		Game();
		~Game();

    /*! init data */
    void init(void);

    /*! act on the events */
    void event( SDL_Event const & event );

		/*! draw the game */
		void render(void);

		/*! update the game */
		void update(void);
	private:
        //several tests, see below for errors:
        //test: UnitManager m_unitManager;  //!< manager of a list of Unit() derived classes
        //UnitManager m_unitManager;
        //rts::UnitManager m_unitManager; //!< manager of a list of Unit() derived classes

        /* the error for 'rts::UnitManager m_unitManager;' is:
            Game.h:48: error: field `m_unitManager' has incomplete type
        */
        //rts::UnitManager m_unitManager; //!< manager of a list of Unit() derived classes

        /* the error for 'UnitManager m_unitManager;' is:
            Game.h:53: error: field `m_unitManager' has incomplete type
        */
        //UnitManager m_unitManager; //!< manager of a list of Unit() derived classes

        /* the error for 'rts::Unit m_test;' is:
            Game.h:58: error: field `m_test' has incomplete type
        */
        //rts::Unit m_test;

        /* the error for 'Unit m_test;' is:
            Game.h:63: error: field `m_test' has incomplete type
        */
        //Unit m_test;
};



} //namespace rts


#endif //RTS_GAME_H





UnitManager.h
//UnitManager.h

#ifndef RTS_UNIT_MANAGER_H
#define RTS_UNIT_MANAGER_H

// About: class that manages a lists of Unit()'s

#include "globals.h" //!< for log
#include <boost/ptr_container/ptr_vector.hpp> //!< for boost::ptr_vector
#include "Actor.h"  //!< for Unit() , But it might move to Unit.h

namespace rts {


class Unit; //!< forward declaration for UnitManager() to see Unit()

/*! a class that manages a list of Unit() derived classes */
class UnitManager
{
	public:
        public:
        /*! typedef for convienence and/or sanity / code clarity */
        typedef boost::ptr_vector<Unit> UnitPtr;

		UnitManager();
		~UnitManager();

        //! add a Unit() derived class to a boost list
        void addUnit( Unit *u );

        //! update all Unit()'s in the list
        void update( float elapsed );

        //! render all Units()'s in the list
        void render( void );

	protected:
	private:
        /*! list of Unit() derived classes using boost::ptr_vector<Unit> */
        UnitPtr m_unitList;
};


} //namespace rts

#endif //RTS_UNIT_MANAGER_H





Actor.h
//actor.h

#ifndef RTS_ACTOR_H
#define RTS_ACTOR_H

// About: Contains base class for unit/building polymorphism

#include <boost/utility.hpp>    //!< for boost::noncopyable
#include "source/jakelib/Vector3d.h" //!< a math/location vector

#include "globals.h"   //<! for jakelib::Graphics2d

namespace rts {

/*! base actor class. Unsure if I want it to be noncopyable */
class Actor : boost::noncopyable
{
    public:
        Actor() : m_location(0,0,0) {}
        Actor(Vector3d loc) : m_location(loc) {}
        virtual ~Actor(){}

        //! update location, keep within screen bounds
        virtual void update(float fps);//was: virtual void update(float elapsed) = 0;

        //! (was pure virtual), derived class overrides to render the unit
        virtual void render(void) {} //was: virtual void render(void) const = 0;

    private:
    protected:
        Vector3d m_location;      //<! coordinates in 2d/3d space

};

/*! Building() derives from Actor(), base class for buildings */
class Building : public Actor
{
	public:
		Building(){}
		virtual ~Building(){}

		/*! update specific to all buildings */
		virtual void update(float elapsed);

		/*! render specific to all buildings */
		virtual void render();

	protected:
	private:
};


/*! Unit() derives from Actor(), base class for units */
class Unit : public Actor
{
	public:
		Unit(){}
		Unit(Vector3d loc) : Actor(loc){}
		virtual ~Unit(){}

        /*! basic update for all units */
		virtual void update(float elapsed);

		/*! basic render for all units */
		virtual void render(void);
	protected:
	private:
};


} //namespace rts

#endif //RTS_ACTOR_H





Thanks, [Edited by - ninmonkeys on June 25, 2006 4:17:50 PM]
Advertisement
Hi,

I'm not used to GCC but I think that if you remove your forward declaration for UnitManager in Game.h and remove your forward declaration for Unit in UnitManager.h it might compile. I've never used boost::ptr_vector but I'm pretty sure it needs the definition of the class, so using a forward declaration wouldn't work. Anyway, when ever you include a header file in which the definition of your class is made, there is no use to forward declare it.

Hope this helps

Eric
I'm not sure what your problem is but I would remove the forward declaration. It might just be confusing the compiler, since the compiler already sees the UnitManager class since it's included.
Quote:Original post by xEricx
Hi,

I'm not used to GCC but I think that if you remove your forward declaration for UnitManager in Game.h and remove your forward declaration for Unit in UnitManager.h it might compile. I've never used boost::ptr_vector but I'm pretty sure it needs the definition of the class, so using a forward declaration wouldn't work.
boost::ptr_vector is like a std::vector of pointers, but it uses 'smart' pointers. (It does reference counting for me)
Quote:xEricx (and Samith's post)
Anyway, when ever you include a header file in which the definition of your class is made, there is no use to forward declare it.
I'm not totally sure why I had the forward include, but I needed one at least in UnitManager. Otherwise if I remove it from UnitManager.h I get:
UnitManager.h:25: error: `Unit' was not declared in this scopeUnitManager.h:25: error: template argument 1 is invalidUnitManager.h:25: error: ISO C++ forbids declaration of `UnitPtr' with no typeUnitManager.h:31: error: `Unit' has not been declaredUnitManager.h:31: error: ISO C++ forbids declaration of `u' with no typeProcess terminated with status 1 (0 minutes, 1 seconds)
I thought the problem might be that Actor.h includes globals.h which included UnitManager.h (so it's seeing it's use in another class before it sees itself defined.) I tried removing that from globals but I still needed to use the forward declaration/include.

Both of the next two tests both are showing the error on the line: rts::UnitManager m_unitManager; //!< manager of a list of Unit() derived classes

In game.h if I don't use the forward include I get an error that I don't know what it means:
Game.h:49: error: using-declaration for non-member at class scopeGame.h:49: error: expected `;' before "m_unitManager"
In game.h If I do use the forward include I get:
Game.h:49: error: field `m_unitManager' has incomplete type
At first glance it looks like you are having difficulty understanding circular dependency... which is when to know when to use an include or a foward declaration.

Start by looking over your dependencies first and you might find the actual problem...

circular dependency
[edit] didnt notice this was actually covered in the article you said you read... but its another explanation anyway....
Note: I'm new to using namespaces.
Quote:Original post by ju2wheels
At first glance it looks like you are having difficulty understanding circular dependency... which is when to know when to use an include or a foward declaration.

Start by looking over your dependencies first and you might find the actual problem...

circular dependency
[edit] didnt notice this was actually covered in the article you said you read... but its another explanation anyway....
I went back and checked. I don't think I am using any circular dependancies, since I'm not doing class A uses class B, and class B uses class A.

Here's my simplified view of the classes.
Actor.h	includes globals.h	defines Actor()	defines Building()	defines Unit()UnitManager.h	includes globals.h	includes boost::ptr_vector	includes Actor.h	defines UnitManager()	uses Unit()Game.h	includes globals.h	includes UnitManager.h	defines Game()	uses UnitManager()globals.h	includes Game.h		defines a graphics object that the classes use


Since I don't think its a circular dependancy, I went and removed all forward includes, and made sure I re-compied all files. Now the errors are
Compiling: Actor.cppIn file included from Game.h:16,                 from globals.h:19,                 from Actor.h:11,                 from Actor.cpp:3:UnitManager.h:24: error: `Unit' was not declared in this scopeUnitManager.h:24: error: template argument 1 is invalidUnitManager.h:24: error: ISO C++ forbids declaration of `UnitPtr' with no typeUnitManager.h:30: error: `rts::Unit' has not been declaredUnitManager.h:30: error: ISO C++ forbids declaration of `u' with no typeProcess terminated with status 1 (0 minutes, 1 seconds)5 errors, 0 warnings
Maybe it's a clue that when compiling Actor.cpp that UnitManager.h is giving errors? I never use UnitManager inside Actor.h/cpp though.

Which are the two lines:
typedef boost::ptr_vector< Unit > UnitPtr;void addUnit( Unit *u );
To see if it was a namespace issue, I also tried:
typedef boost::ptr_vector< rts::Unit > UnitPtr;void addUnit( rts::Unit *u );


I also tried removing all namespaces from all my files, but I end up with the same error. I then tried a forward-include (even though I think that's the wrong usage, but don't know what else to do) in UnitManager.h and UnitManager.h then compiles, but Game.h trying to use a UnitManager doesn't compile because of the 'does not name a type' error again.

I don't know what else to try.
Try working backwards...

in main just include the actor header and see if it compiles by itself. Then add the other headers one by one... there might be some subtle error somewhere but the compiler is just spitting out nonsense.

dumb question as most of the code you posted has it... is globals.h wrapped with inclusion guards?
Quote:Original post by ninmonkeys
boost::ptr_vector is like a std::vector of pointers, but it uses 'smart' pointers. (It does reference counting for me)


Actually, boost::ptr_vector is a container for pointers to exclusively-owned objects. It uses void* pointers, not smart pointers, so there is no reference count.

http://www.boost.org/libs/ptr_container/doc/ptr_container.html
Quote:
The disadvantages are

1. Less flexible than containers of smart pointers like boost::shared_ptr
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Quote:Original post by ju2wheels
Try working backwards...

in main just include the actor header and see if it compiles by itself. Then add the other headers one by one... there might be some subtle error somewhere but the compiler is just spitting out nonsense.

dumb question as most of the code you posted has it... is globals.h wrapped with inclusion guards?
Alone the code is compiling, but together it's a problem.

I found that in Actor.h, the line '#include "globals.h"' is what's causing the problem. So it looks like something is causing it to spit out nonsense. I don't think it's related to any sources prefixed with "source/jakelib" since I've used them in other programs.

I have a graphics object that I need to include to be able to render. I don't see anything in globals.h/cpp that should cause a problem. I'm also using defines to prevent multiple inclusion of the same file. That's what 'inclusion guards' are right?

Error if I include globals.h in Actor.h
Switching to target: defaultCompiling: Actor.cppIn file included from Game.h:15,                 from globals.h:19,                 from Actor.h:10,                 from Actor.cpp:3:UnitManager.h:18: error: `Unit' was not declared in this scopeUnitManager.h:18: error: template argument 1 is invalidUnitManager.h:18: error: ISO C++ forbids declaration of `UnitPtr' with no typeUnitManager.h:24: error: `Unit' has not been declaredUnitManager.h:24: error: ISO C++ forbids declaration of `unit' with no typeProcess terminated with status 1 (0 minutes, 1 seconds)5 errors, 0 warnings


globals.h
//globals.h#ifndef RTS_GLOBALS_H#define RTS_GLOBALS_H#include <iostream>#include "sdl.h" //!< libSDL//game modules#include "GameMap.h" //!< map related classes/functions/and types#include "Game.h"   //!< main game logic//jakelib (my libs)#include "source/jakelib/log.h" //!< basic logging: jakelib::Log()#include "source/jakelib/jakeGraphics2d.h"  //!< my graphics wrapper#include "source/jakelib/Vector2d.h" //!< a templated 2d array using std::vector#include "source/jakelib/jakeSDL_ttf.h" //!< helper functions for SDL_ttf#include "source/jakelib/Vector3d.h" //!< a math/location vector, might be an old versioinextern bool bDone; //!< if true, quits the game (at least main loop)extern const std::string APP_VERSION; //!< window title, and console output// == screen ==extern int screen_w;        //!< screen widthextern int screen_h;        //!< screen heightextern int screen_tiles_x;  //!< number of tiles on the x-axisextern int screen_tiles_y;  //!< number of tiles on the y-axisextern int tiles_w; //!< width of tilesextern int tiles_h; //!< height of tiles// == font ==extern int font_size;   //!< font height in pixels//fps() related variables:extern unsigned int fps_timer;  //!< current tickextern float fps_elapsed;  //!< multiply speed per sec by thisextern unsigned int fps_frametimer;	//!< (need to check)extern int fps_counter;	//!< (need to check)extern int fps_fps;   //!< frames per second, actual FPSextern int fps_avg;   //!< average frames per second// ==== structs ====struct MouseData{    MapCoord localCoord;    //!< local coord mouse is hovering    MapCoord worldCoord;    //!< world coord mouse is hovering};// ==== class/struct instances ====extern jakelib::Log Log; //!< global log instance for anyone including globals.hextern jakelib::Graphics2d graphics;   //!< instance of my SDL graphics wrapperextern jakelib::Vector2d<MapTile> Map;  //!< map dataextern jakelib::FontObject font;       //!< instance of my helper functions/wrapper to SDL_ttf// == map ==extern MapCoord mapTopLeft; //!< map(x,y) = screen(x,y) + mapTopLeftextern MouseData mouse;     //!< misc mouse stats / states information// ==== functions ====//! returns a SDL_Color based on r,g,b valuesSDL_Color getSDL_Color(int r, int g, int b);//! random int from min to max (inclusive)int Rand(int min, int max);//!calculate the FPS, and set FPS related variablesfloat fps(void);//}//namespace: rts (game's namespace )#endif // RTS_GLOBALS_H


globals.cpp
//globals.cpp#include "globals.h"bool bDone = false; //!< if true, quits the game (at least main loop)//! window title, and console outputconst std::string APP_VERSION = "RTS v0.8 (2006/06/28)";// == screen ==int screen_tiles_x = 0; //!< number of tiles on the x-axisint screen_tiles_y = 0; //!< number of tiles on the y-axisint screen_w = 1024;           //!< screen widthint screen_h = 768;           //!< screen heightint tiles_w = 16;            //!< width of tilesint tiles_h = 16;            //!< height of tiles// == font ==int font_size = 16;   //!< font height in pixels// == variables for for fps() ==unsigned int fps_timer;  //!< current tickfloat fps_elapsed;  //!< multiply speed per sec by thisunsigned int fps_frametimer;	//!< (need to check)int fps_counter;	//!< (need to check)int fps_fps;   //!< frames per second, actual FPSint fps_avg;   //!< average frames per second// ==== structs ====// == map == todo: move to map.hMapCoord mapTopLeft( 0,0 ); //!< map(x,y) = screen(x,y) + mapTopLeftMouseData mouse;     //!< misc mouse stats / states information// ==== class instances ====jakelib::Log Log("general"); //!< global log instance for anyone including globals.hjakelib::Graphics2d graphics;   //!< instance of my SDL graphics wrapperjakelib::Vector2d<MapTile> Map;  //!< map data    //was: jakelib::Vector2d<MapTile> Map; //<! map datajakelib::FontObject font;       //!< instance of my helper functions/wrapper to SDL_ttf// == map ==// ==== functions ====//! returns a SDL_Color based on r,g,b valuesSDL_Color getSDL_Color(int r, int g, int b){    SDL_Color tmp;    tmp.r = r;    tmp.g = g;    tmp.b = b;    return tmp;}//! random int from min to max (inclusive)int Rand(int min, int max){  return ((rand() % (max-min+1)) + min);}//!called every render update, does fps mathfloat fps(void) {	//multiply speed per second by return value to get the distance to update this frame		// (speed per second)*fps_elapsed = speed_this_frame    fps_elapsed = (SDL_GetTicks() - fps_timer)/(1000.0f);    fps_timer = SDL_GetTicks();    if(fps_timer - fps_frametimer >= 1000) {        fps_frametimer = fps_timer;        fps_fps = fps_counter;        fps_avg += fps_fps;        fps_avg /= 2;        fps_counter = 0;    }    else {        fps_counter += 1;    }    return fps_elapsed;//speed per second multiplier}
Quote:I'm also using defines to prevent multiple inclusion of the same file. That's what 'inclusion guards' are right?

Yes.

Why are globals.h and game.h including each other instead of just game.h including globals.h?

This topic is closed to new replies.

Advertisement