Troubles with Headers

Started by
8 comments, last by erissian 16 years, 10 months ago
Thanks to all who replied. I've got it working now thanks to you and am on my way to clean code! This is for C++. So I spent a few months and made my own fully working game with everything I wanted. It was great on the outside, but on the inside was one big bloated source file with all my classes in it. I tried early in that project to make separate .cpps but it was too late. So I just did the whole game in one file. Now I'm starting a new game and would like to separate most of the classes, but I have no idea what a header file is or why they exist. This is the structure I have right now. main.cpp includes Player.h Player.h includes Entity.h(Entity is the base class for all game objects, so the player class inherits from entity) Entity.h includes Render.h Render.h includes all the rest of the files I need. They all have include guards around them. All the .cpp files include their .h counterparts. I'm getting a compile error that says Entity base class undefined. So I put class Entity; in the Entity.h file. Same error. Maybe I need an interface in the .h? Ok, so I copy my class and strip out all the methods so they go something likes this void method(); int otherMethod(); Now I'm getting a class type redefinition error. I've searched around and can't find any information that deals with these kinds of problems I've been having with header files and separating my classes from one giant .cpp file. Any ideas or resources that can help me get this all sorted out? [Edited by - agoaj on June 17, 2007 4:25:04 AM]
Advertisement
Someone correct me if I'm wrong(it's late).

I'm not sure if you said this, but when you link files together, if you have a Entity.h(declaration) file and its Entity.cpp(implementation) files separate, you don't need to link your Entity.cpp file to anything, just the Entity.h, and the only thing Entity.cpp needs linked to it is Entity.h, and if it is a derived class it will need the the .h file for its parent.

Quote:
So I put class Entity; in the Entity.h file. Same error. Maybe I need an interface in the .h?

I'm not quite sure I follow. What's in your .h file? Your .h file should look something like this:
// Entity.h class Entity{ private:   int data;   more data public:   int GetData();   ...};

That is your declaration, your implementation is when you define your member functions, ie int GetData().
So your Entity.cpp file should look like
#include "Entity.h"int Entity::GetData(){  return data;}...more member function implementations...

I'm confused when you say "Maybe I need an interface in the .h?" because your interface is just your class declaration. Perhaps you meant something else?

If you can't get it to work, just post your source and someone will make the corrections.

Quote:
Now I'm starting a new game and would like to separate most of the classes, but I have no idea what a header file is or why they exist.


A header is just your declarations, and although it may seem unnecessary for a relatively small project, its functionality really shines when the project gets huge. It allows you to keep the functioning code away from the interface, which is important because the code will just clutter up the file, and once its written and functional you don't need to see it, you just need to see the declarations so you know what your functions are. In other words, once you define your UpdateEntity() function, you don't care to see it over and over, all you need to see is your declarations that show you that you have the UpdateEntity() function at your disposal.
Also, if you have your implementations in the same file as your declarations, when you include that file in your main.cpp, all that implementation code will be included as well, which is unnecessary, all you need is the declaration.
I found this article to be really helpful in understanding how to organize your code. As for your errors, it sounds like you need to try including the files in a different order, or you forgot an inclusion guard somewhere.
This is what I have in Entity.cpp
#include "Entity.h"class cEntity {  protected:	int x;	float xv;	int y;	float yv;	int offset;	int level;	unsigned int frameCount;	float time;	bool vfaceleft;	gxSprite sprite;	Collision colbox;public: cEntity () {  			x = 0;			y = 0;			offset = 0;			level = 0;			vfaceleft = false;			time = 0;		}		cEntity (int sx, int sy, int soffset) {  			this->offset = offset;			level = 0;			this->x = sx;			this->y = sy;			vfaceleft = false;			time = 0;			colbox.update(x,y, x + sprite.width, y + sprite.height);			updateCollision();		}		void updateCollision()		{			colbox.update(x, y, x + sprite.width, y + sprite.height);		}		void updateCollision(bool alt){			//Used exclusively for mario.			colbox.update(x + globalOffset, y, x + globalOffset + sprite.width, y + sprite.height);		}		bool checkCollision(Collision box)		{			return colbox.collidedWith(box);		}		Collision collisionBox()		{			return colbox;		}		int getFrameCount(){			return this->frameCount;		}		void resetFrameCount(){			frameCount = 0;		}		void incFrameCount(){			frameCount++;		}		void render(){			crender().character(sprite, this->X(), this->Y());		}		void renderInvert(){			crender().characterInvert(sprite, this->X(), this->Y());		}		// Special render method, if you need the sprite drawn somewhere else.		void render(int x){			crender().character(sprite, x, this->Y());		}		void renderInvert(int x){			crender().characterInvert(sprite, x, this->Y());		}		bool faceleft(){			if(this->xV() > 0)				vfaceleft = false;			else if(this->xV() < 0)				vfaceleft = true;			return vfaceleft;		}		virtual int X(){			return this->x;		}		float xV(){			return xv;		}		void setx(int x){			this->x = x;			updateCollision();		}		void setxV(float v){				this->xv = v;		}		virtual int Y(){ 			return this->y; 		}		void sety(int y){			this->y = y;			updateCollision();		}		void setyV(float v){			this->yv = v;		}		float yV(){			return yv;		}		/*		Returns the speed. Sqrt(A^2 + B^2)		*/		int getVelocity(){			return((int)sqrt((this->xV() * this->xV() + this->yV() * this->yV())));		}		virtual int Offset(){ 			return this->offset; 		} 		void setOffset(int x){			this->offset = x;		}}; 

and this is Entity.h
#ifndef ENTITY_H#define ENTITY_H#include "render.h"class cEntity {  	protected:	int x;	float xv;	int y;	float yv;	int offset;	int level;	unsigned int frameCount;	float time;	bool vfaceleft;	gxSprite sprite;	Collision colbox;public: cEntity ();		cEntity (int sx, int sy, int soffset);		void updateCollision();		void updateCollision(bool alt);		bool checkCollision(Collision box);		Collision collisionBox();		int getFrameCount();		void resetFrameCount();		void incFrameCount();		void render();		void renderInvert();		// Special render method, if you need the sprite drawn somewhere else.		void render(int x);		void renderInvert(int x);		bool faceleft();		virtual int X();		float xV();		void setx(int x);		void setxV(float v);		virtual int Y();		void sety(int y);		void setyV(float v);		float yV();		int getVelocity();		virtual int Offset();		void setOffset(int x);}; #endif


I'm getting error C2011: 'cEntity' : 'class' type redefinition
when I compile that.
The definition of the class ("class cEntity { ... };") should be in the header file only. Remember, #include directives are simple textual replacement. The contents of the included file is copied wholesale into the contents of the including file at the point of the directive; by including the header and replicating the class definition in the .cpp file, the final preprocessed file ends up with two definitions of the class, which is illegal, and thus the compiler compilers.

So remove the class definition from the .cpp file.

You will still want to define the methods in the .cpp file (in general; ignoring inlining issues). You do not need to reopen the class definition for this, you can simply using the :: operator to resolve to the appropriate scope:
bool cEntity::checkCollision(Collision box){  return colbox.collidedWith(box);}


If this is unfamiliar to you, you might want to check out the appropriate chapters on classes in C++ in the online books Thinking in C++ and/or C++: A Dialog.
Only put the "class cEntity { ... };" bit in the header.

To implement the functions in the header, use:

return_type class_name::function_name( argument_type argument_name, ... )
{
}

Example of the first few functions.

Header:
#ifndef ENTITY_H#define ENTITY_H#include "render.h"class cEntity {  	protected:	int x;	float xv;	int y;	float yv;	int offset;	int level;	unsigned int frameCount;	float time;	bool vfaceleft;	gxSprite sprite;	Collision colbox;public: cEntity ();		cEntity (int sx, int sy, int soffset);		void updateCollision();		void updateCollision(bool alt);		bool checkCollision(Collision box);		Collision collisionBox();		int getFrameCount();		void resetFrameCount();		void incFrameCount();		void render();		void renderInvert();		// Special render method, if you need the sprite drawn somewhere else.		void render(int x);		void renderInvert(int x);		bool faceleft();		virtual int X();		float xV();		void setx(int x);		void setxV(float v);		virtual int Y();		void sety(int y);		void setyV(float v);		float yV();		int getVelocity();		virtual int Offset();		void setOffset(int x);}; #endif


Source:
cEntity::cEntity(){          x = 0;	y = 0;	offset = 0;	level = 0;	vfaceleft = false;	time = 0;}cEntity::cEntity (int sx, int sy, int soffset){  	this->offset = offset;	level = 0;	this->x = sx;	this->y = sy;	vfaceleft = false;	time = 0;	colbox.update(x,y, x + sprite.width, y + sprite.height);	updateCollision();}void cEntity::updateCollision(){	colbox.update(x, y, x + sprite.width, y + sprite.height);}void cEntity::updateCollision(bool alt){	//Used exclusively for mario.	colbox.update(x + globalOffset, y, x + globalOffset + sprite.width, y + sprite.height);}/*... rest of cEntity functions in the same style ...*/


Finally, why call your class "cEntity"? Why not just "Entity"?
Quote:Original post by rip-off
Only put the "class cEntity { ... };" bit in the header.

To implement the functions in the header, use:

return_type class_name::function_name( argument_type argument_name, ... )
{
}

Example of the first few functions.

Header:
*** Source Snippet Removed ***

Source:
*** Source Snippet Removed ***

Finally, why call your class "cEntity"? Why not just "Entity"?


I'm still getting a redefinition error. I've changed Entity.cpp like you said
#include "Entity.h"class Entity {  protected:	int x;	float xv;	int y;	float yv;	int offset;	int level;	unsigned int frameCount;	float time;	bool vfaceleft;	gxSprite sprite;	Collision colbox;public: Entity::Entity () {  			x = 0;			y = 0;			offset = 0;			level = 0;			vfaceleft = false;			time = 0;		}		Entity::Entity (int sx, int sy, int soffset) {  			this->offset = offset;			level = 0;			this->x = sx;			this->y = sy;			vfaceleft = false;			time = 0;			colbox.update(x,y, x + sprite.width, y + sprite.height);			updateCollision();		}		void Entity::updateCollision()		{			colbox.update(x, y, x + sprite.width, y + sprite.height);		}		void Entity::updateCollision(bool alt){			//Used exclusively for mario.			colbox.update(x + globalOffset, y, x + globalOffset + sprite.width, y + sprite.height);		}		bool Entity::checkCollision(Collision box)		{			return colbox.collidedWith(box);		}		Collision Entity::collisionBox()		{			return colbox;		}		int Entity::getFrameCount(){			return this->frameCount;		}		void Entity::resetFrameCount(){			frameCount = 0;		}		void Entity::incFrameCount(){			frameCount++;		}		void Entity::render(){			crender().character(sprite, this->X(), this->Y());		}		void Entity::renderInvert(){			crender().characterInvert(sprite, this->X(), this->Y());		}		// Special render method, if you need the sprite drawn somewhere else.		void Entity::render(int x){			crender().character(sprite, x, this->Y());		}		void Entity::renderInvert(int x){			crender().characterInvert(sprite, x, this->Y());		}		bool Entity::faceleft(){			if(this->xV() > 0)				vfaceleft = false;			else if(this->xV() < 0)				vfaceleft = true;			return vfaceleft;		}		virtual int Entity::X(){			return this->x;		}		float Entity::xV(){			return xv;		}		void Entity::setx(int x){			this->x = x;			updateCollision();		}		void Entity::setxV(float v){				this->xv = v;		}		virtual int Entity::Y(){ 			return this->y; 		}		void Entity::sety(int y){			this->y = y;			updateCollision();		}		void Entity::setyV(float v){			this->yv = v;		}		float Entity::yV(){			return yv;		}		/*		Returns the speed. Sqrt(A^2 + B^2)		*/		int Entity::getVelocity(){			return((int)sqrt((this->xV() * this->xV() + this->yV() * this->yV())));		}		virtual int Entity::Offset(){ 			return this->offset; 		} 		void Entity::setOffset(int x){			this->offset = x;		}}; 


and Entity.h is the same as before.
Quote:
I'm still getting a redefinition error. I've changed Entity.cpp like you said

class CLASSNAME { stuff }; is the definition of class. That cannot be in the .cpp file. Look at rip-off's example, again, and note how he does not have class cEntity {... in the source file.

I think you would do well to read the links I gave you, as they have pretty clear descriptions of what exactly is going on here, including the difference between the definition of the class and the definitions of its member functions, et cetera.

class Entity {  protected:	int x;	float xv;	int y;	float yv;	int offset;	int level;	unsigned int frameCount;	float time;	bool vfaceleft;	gxSprite sprite;	Collision colbox;//etc etc}


above is belong to .h file.

put only these on .cpp file

Entity::Entity (int sx, int sy, int soffset) {  			this->offset = offset;			level = 0;			this->x = sx;			this->y = sy;			vfaceleft = false;			time = 0;			colbox.update(x,y, x + sprite.width, y + sprite.height);			updateCollision();		}		void Entity::updateCollision()		{			colbox.update(x, y, x + sprite.width, y + sprite.height);		}		void Entity::updateCollision(bool alt){			//Used exclusively for mario.			colbox.update(x + globalOffset, y, x + globalOffset + sprite.width, y + sprite.height);		}		bool Entity::checkCollision(Collision box)		{			return colbox.collidedWith(box);		}		Collision Entity::collisionBox()		{			return colbox;		}		int Entity::getFrameCount(){			return this->frameCount;		}		void Entity::resetFrameCount(){			frameCount = 0;		}		void Entity::incFrameCount(){			frameCount++;		}		void Entity::render(){			crender().character(sprite, this->X(), this->Y());		}		void Entity::renderInvert(){			crender().characterInvert(sprite, this->X(), this->Y());		}		// Special render method, if you need the sprite drawn somewhere else.		void Entity::render(int x){			crender().character(sprite, x, this->Y());		}		void Entity::renderInvert(int x){			crender().characterInvert(sprite, x, this->Y());		}		bool Entity::faceleft(){			if(this->xV() > 0)				vfaceleft = false;			else if(this->xV() < 0)				vfaceleft = true;			return vfaceleft;		}		virtual int Entity::X(){			return this->x;		}		float Entity::xV(){			return xv;		}		void Entity::setx(int x){			this->x = x;			updateCollision();		}		void Entity::setxV(float v){				this->xv = v;		}		virtual int Entity::Y(){ 			return this->y; 		}		void Entity::sety(int y){			this->y = y;			updateCollision();		}		void Entity::setyV(float v){			this->yv = v;		}		float Entity::yV(){			return yv;		}		/*		Returns the speed. Sqrt(A^2 + B^2)		*/		int Entity::getVelocity(){			return((int)sqrt((this->xV() * this->xV() + this->yV() * this->yV())));		}		virtual int Entity::Offset(){ 			return this->offset; 		} 		void Entity::setOffset(int x){			this->offset = x;		}
How I organize my files:

Typically, I have a group of files that revolve around my core program. These are files like my renderer, my input handling, miscellaneous state functions, etc. These all share one header file that has function declarations, preprocessing directives, etc.

Secondly, I have a few files that are more or less library routines. Things that are not specific to that program, that are likely to be reused, but don't necessarily deserve a class of their own. Things like interpolation functions, or random number generators. Each set of functions is in their own source file with their own header.

Then I have classes. These files rarely have more than one class in them; they get their own source file and corresponding header.

In general, I try to keep the includes in the source file as much as possible. I don't like to clutter up the header. The only time I move includes to the header is when I need to.

For instance:

//mouse.h#ifndef EG_MOUSE_H#define EG_MOUSE_H#include "mouseears.h"#include "entities.h"class Mouse {  Entities *entities;  MouseEars ears;  void hear();  void pellet();};#endif

//mouse.cpp#include "mouse.h"#include "mousepellet.h"void Mouse::hear() {  ears.hear();}void Mouse::pellet() {  entities->add(new MousePellet);}

Now, I included mousepellet.h in the source file, because it keeps the header clean. I included entities.h and mouseears.h in the header because I needed those type in the class declaration.

The other problem I run into is whether I should include files that are included by other files. If mouseears.h included entities.h, then should I include it again? Is that redundant? Does it confuse how the system is abstracted?

In general, I try not to include files that I don't explicitly refer to. I include entities.h because I explicitly use the Entities class. If I decided to remove MouseEars from this class, I would still need Entities, therefore it gets included.

Let's say that there was another fictional class, ListeningEar, which allows the MouseEars to function. Even though I am using the hear() function, it's only abstracted through the MouseEars class, so I don't include it explicitly. If I take out MouseEars, then there's no other reason I would ever need to have that include, so it doesn't make the cut.

Let's say this was all for a program called mouserace. I don't include "mouserace.h" because this class is completely isolated. If I have some other program that uses the same Entities and ListeningEar class, then there's nothing preventing me from using my Mouse class in that program too. By not including that header (since there's no pressing need to) I'm making it easier to reuse the code.

I can't say that mine is the best way, as I'm sure there are better, but hopefully it gives you some insight into how you might organize your files. (And hopefully this answer was somehow related to your question :) )
We''re sorry, but you don''t have the clearance to read this post. Please exit your browser at this time. (Code 23)

This topic is closed to new replies.

Advertisement