views:

141

answers:

6

Hi

I've been working with C++ for a good couple of weeks now, but the mechanism behind header files (or the linker I suppose?) confuses the heck out of me. I've gotten in the habit of creating a "main.h" to group my other header files and keep the main.cpp tidy, but sometimes those header files complain about not being able to find a different header file (even though it's declared in the "main.h"). I'm probably not explaining it very well so here's an abridged version of what I'm trying to do:

//main.cpp

#include "main.h"
int main() {
    return 0;
}

-

//main.h

#include "player.h"
#include "health.h"
#include "custvector.h"

-

//player.h

#include "main.h"
class Player {
    private:
        Vector playerPos;
    public:
        Health playerHealth;
};

-

//custvector.h

struct Vector {
   int X;
   int Y;
   int Z;
};

-

//health.h
class Health {
    private:
        int curHealth;
        int maxHealth;
    public:
        int getHealth() const;
        void setHealth(int inH);
        void modHealth(int inHM);
};

I won't include health.cpp because it's a bit lengthy (but does work), it does have #include "health.h".

Anyways, the compiler (Code::Blocks) complains that "player.h" can't find the types 'Health' or 'Vector'. I thought that if I used #include "main.h" into "player.h" it would be able to find the definitions for Health and Vector sense they're included in "main.h". I figured they would they would sort of tunnel their way though (player.h -> main.h -> health.h). But that didn't work too well. Is there some kind of a diagram or video that could clarify how this should be set up? Google wasn't much help (nor my book).

Thanks for any help,

Karl

+1  A: 

You have a circular dependency. Player includes main.h, but main.h includes player.h. Resolve this by removing one dependency or the other.\

Player.h should include health.h and custvector.h, and at this point, I don't think main.h needs any includes. Eventually it may need player.h.

reuscam
#ifndef ... #endif is another, slightly easier way to go as well
Chris Thompson
Won't that be a problem if something else needs to use health.h? Wouldn't that include it into the program twice?
Karl Menke
The way to avoid including a header file multiple times in C or C++ is to use an include guard. Each header file starts with the two lines `#ifndef UNIQUE_STRING` and `#define UNIQUE_STRING` (replacing UNIQUE_STRING with some name that you don't `#define` elsewhere). The file then ends with `#endif`. http://en.wikipedia.org/wiki/Include_guard
Josh Townzen
+2  A: 

includes work very simple, they just command preprocessor to add the contents of the file to where include is set. basic idea is to include headers that you depend on. in player.h you should include custvector.h and Health.h. In main only player.h, because all needed includes will be carried with player. and you don't need to include main.h in player.h at all.

it is good also to make sure that header is included only once. in this question general solution is given http://stackoverflow.com/questions/672734/how-to-prevent-multiple-definitions-in-c in case of Visual Studio you can use #pragma once, if Borland c++ there is also a trick but i forgot it.

Andrey
I guess that's what I was concerned about, I didn't want to add it twice if I decided to make something like a Enemy class that also needed Vector and Health. I figured if I put all the definitions into main.h, it would eliminate that problem.
Karl Menke
@Karl Menke `main.h` is not good place to put it, because it will also contain things for main.cpp. you should create something like `common.h` and move the common references there. then use it.
Andrey
+7  A: 

The best way to think of your header files are as an "automated copy-and-paste".

A good way to think about it (although not how this is actually implemented) is that when you compile a C file or C++ file, the preprocessor runs first. Every time it encounters an #include statement, it will actually paste the content of that file instead of the #include statement. This is done until there are no more includes. The final buffer is passed to the compiler.

This introduces several complexities:

First, if A.H includes B.H and B.H includes A.h, you've got a problem. Because every time you want to paste A, you would need B and it would internally have A ! That's a recursion. For this reason, header files use #ifndef, to ensure that the same part is not read multiple times. This is likely happening in your code.

Second, your C compiler reads the file after all the header files have been "flattened", so you need to consider that when reasoning about what is declared before what.

Uri
That's the explanation I like more, and the one I that describes best how I understand this problem. It's simple, the compiler takes text and compiles it. The preprocessor takes text and preprocess it. Includes are just a preprocessor directive to IMPORT some text from an external file into the current file.
Spidey
Thanks, that helps.
Karl Menke
@Uri, +1 Simple and cool.. :)
liaK
+1  A: 

Is there some kind of a diagram or video that could clarify how this should be set up?

Try my answer to the question to the question "Clean up your #include statements?".

ChrisW
Thanks, I'll take a look at that.
Karl Menke
@Karl Menke -- There's another [here](http://stackoverflow.com/questions/1598207/odd-circular-dependency-issue/1598257#1598257)
ChrisW
+3  A: 

The other answers here have effectively explained the way header files and the preprocessor work. The biggest problem you have is the circular dependencies, which from experience, I know can be a royal pain. Also, when that starts happening, the compiler starts to behave in very odd ways and throw error messages that aren't super helpful. The method I was taught by a C++ guru in college was to start each file (a header file for instance) with

//very beginning of the file
#ifndef HEADER_FILE_H //use a name that is unique though!!
#define HEADER_FILE_H
...
//code goes here
...
#endif
//very end of the file

This uses preprocessor directives to automatically prevent circular dependencies. Basically, I always use an all uppercase version of the file name. custom-vector.h becomes

#ifndef CUSTOM_VECTOR_H
#define CUSTOM_VECTOR_H

This allows you to include files willie-nillie without creating circular dependencies because if a file is included multiple times, its preprocessor variable is already defined, so the preprocessor skips the file. It also makes it easier later on to work with the code because you don't have to sift through your old header files to make sure you haven't already included something. I'll repeat again though, make sure the variable names you use in your #define statements are unique for you otherwise you could run into problems where something doesn't get included properly ;-).

Good luck!

Chris Thompson
Hope you don't mind: I edited out your CUSTOM_VECTOR_CPP example. `*.c` and `*.cpp` files don't need include guards since you don't #include them.
John Kugelman
So for example, if I were to make a Enemy class that needed Vector and Health, and Player class already included Vector and Health, I wouldn't need to include them for Enemy?
Karl Menke
@John No problem! Good call, I'm used to template programming where you have to include the *.cpp files in the *.h files. I've just gotten in the habit of doing it :-)
Chris Thompson
@Karl right, think of the preprocessor of creating a giant file with all of the included files in it. The compiler then operates over that large file. So once a file has been included regardless of where from, the compiler is able to find it. Does that make sense?
Chris Thompson
That does make sense. I guess my only issue left is keeping track of where it's included. Say for instance I want to remove a file that contains a Class that uses both of those types, but that file also has the #include for both types. So both types wouldn't be included anymore (but say I have other classes that still need them). Would it be better then to have the #include for both types in every file that uses them if that happens? If the preprocessor is going to catch them, it doesn't seem like it would matter.
Karl Menke
@Karl I'm inclined to say just include it everywhere it's needed and use the `#ifndef ... #define` blocks to prevent circular includes. That way there's no potential for it to get cut out later. Also that way your code is semi self-sufficient rather than dependent on other, unrelated code. That might be a good "best practices" question for SO though. Regardless, as long as you use the #define blocks correctly, you won't have any problems if you include a file too many times
Chris Thompson
+1  A: 

You want to organize your #includes (and libraries, for that matter) in a DAG (directed, acyclic graph). That's the complicated way of saying "avoid cycles between header files":

If B includes A, A should not include B.

So, using "one big master main.h" is not the right approach, because it's hard to #include only direct dependencies.

Each .cpp file should include its own .h file. That .h file should only include things that it itself requires to compile.

There is usually no main.h, because main.cpp nobody needs the definition of main.

Furthermore, you'll want include guards to protect you against multiple includes.

For example

//player.h
#ifndef PLAYER_H_
#define PLAYER_H_
#include "vector.h"  // Because we use Vector
#include "health.h"  // Because we use Health
class Player {
    private:
        Vector playerPos;
    public:
        Health playerHealth;
};
#endif

-

//vector.h
#ifndef VECTOR_H_
#define VECTOR_H_
struct Vector {
   int X;
   int Y;
   int Z;
};
#endif

-

//health.h
#ifndef HEALTH_H_
#define HEALTH_H_
class Health {
    private:
        int curHealth;
        int maxHealth;
    public:
        int getHealth() const;
        void setHealth(int inH);
        void modHealth(int inHM);
};
#endif

The only time you want to aggregate a bunch of #includes into a single header is when you're providing it as a convenience for a very large library.

In your current example, you're going a little overboard - each class doesn't need its own header file. It can all go in main.cpp.

The c preprocessor literally inserts the file from a #include into the file that includes it (unless it has already been inserted, which is why you need the include guards). It allows you to use the classes defined in those files because you now have access to their definition.

Stephen