For the sake of this analysis, I'm going to assume that the contents of "globals.h" does not depend on any of your object classes.
The standard solution to this is as follows:
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
void someFunction(/* ... */);
#endif
globals.cpp
#include "globals.h"
void someFunction(/* ... */) {
// ...
}
object.h
#ifndef OBJECT_H
#define OBJECT_H
class Object
{
public:
virtual ~Object();
virtual void frobnicate() = 0;
// ...
};
#endif
object.cpp
#include "object.h"
Object::~Object()
{
}
bullet.h
#ifndef BULLET_H
#define BULLET_H
#include "object.h"
class Bullet : public Object
{
public:
virtual void frobnicate();
};
#endif
bullet.cpp
include "bullet.h"
#include "globals.h"
void Bullet::frobnicate()
{
// ...
someFunction(/* ... *);
// ...
}
main.cpp
#include "bullet.h"
int main()
{
Bullet bullet;
bullet.frobnicate();
}
Now, this is just the structural overview. We see that the general structure of a header file is that it has include guards, which should be directly related to the file name to avoid collisions. There is no need to use lots of underscores, a simple _H suffix will ensure that it doesn't collide with sane macros. If you wish, you can use #pragma once instead of, or in addition to, include guards.
The next thing to note is that, in general, we do not put implementations in the header files. This is possibly what is causing the "multiple definitions" error you alluded to (I will talk about this in a moment).
Finally, each header file only #includes files it actually depends on. In some cases, a forward declaration will suffice, but for inheritance you need a full class definition. You'll note I put the #include "globals.h" inside bullet.cpp, rather than in bullet.h.
Also note that each source file includes its header file as the very first line. This is very important, because otherwise you can get very brittle header files that depend on the order of inclusion. What you want is for each of your header files to compile correctly in isolation (as I mention below, header files aren't really compiled themselves).
oh i almost forgot i dont know if this will be relevant but my globals.h has both declaration and definitions should i seperate them into a .h and a .cpp?
[/quote]
Header files should not contain variable or function definitions. No amount of include guards or pragma once can defend against this. It is critical to understand the C++ compilation process, which I will call the "build" process here to avoid the confusion between the overall process (called compiling) and one particular stage in that process (also called compiling).
The basic overview is that we have three stages, preprocessing, compiling and linking. The output of each stage is fed to the next. An important point is that only "source files" are built. That is, files that end in .c or .cpp. Headers are only built by including them in one or more source files.
The pre-processing stage is the simplest. Each source file is fed into the pre-processor independently. All the #includes, #defines and #if...#endif and #pragmas are evaluated. Note that #include here is a simple copy/paste operation, the pre-processor literally pretends you wrote all the code in that file.
It is critical to note that the pre-processor doesn't understand C++, it only understands #include, #define etc. If the result of the pre-processing stage is total gibberish, then this is what the compiler stage will see, and complain about. Certain classes of compile errors are hard to diagnose because information can be essentially "lost in translation".
The output of of the pre-processing stage is called a "translation unit".
Each translation unit is then compiled in isolation. Here, the compiler parses the c++, tries to understand it, makes sure you obey all the rules, and finally outputs a "object file". The terminology "object file" pre-dates C++, and has nothing to do with object oriented programming or classes. The terminology really refers to data and function definitions as "objects". On Windows systems, object files will be something like main.obj or bullets.obj. On Unix derivatives, these would be called main.o or bullets.o.
The inner details of the compilation stage is a complex but interesting process, much more could be written about it, which I will not do so here. This is just an overview.
Finally, we have a bunch of object files, one for each source file. The link stage tries to put them together to form an executable. Here it must resolve references to data and functions, i.e. the "objects" referred to earlier. If all goes according to plan, the linker will output an executable file. Roughly speaking, object files list the references they need and the references they require. For example, bullet.o says "I provide Bullet::frobnicate, but I require someFunction", object.o says "I provide Object::~Object", globals.o says "I provide someFunction". main.o says "I require Bullet::frobnicate, Object::~Object, I provide the entry point (main)" (again, a simplification - there are other symbols required for virtual functions, etc).
This is the build process. If you are interested, you can force your toolchain to output the various intermediate files (object files are typically output by default, to enable incremental builds).
Now that you hopefully have an idea of what is going on, we can track down this error. What happens if you have a "globals.h" file that contains function definitions? Well, if it is included only once, it will end up in exactly one translation unit, and in one object file. When the linker links this with the other object files, it will not find any name collisions and all will work.
However, if two (or more) different source files end up including such a header (directly or indirectly), then the function bodies will end up in two translation units. These are compiled in isolation, so we will get two object files which both say "I have an implementation of someFunction". Linkers are pretty stupid, if the linker finds multiple pieces of data or function bodies with the same name it will complain, even if they are identical!
Also to go back to the earlier point about trying to write header files that would compile in isolation. You can see now the difficulty - header files aren't compiled, except when included. By including them as the first line in a source file, we ensure that this header file would compile if it were actually compiled itself. Well, almost. It is possible to do silly things that will break this assumption (a simple example is to omit the closing semi-colon on the class body, and include it in the second line of the associated source file).