Include problems

Started by
11 comments, last by rip-off 12 years ago
Hi Guys,

i always seem to get this problem even after searching the web and i feel its time to get closure.

i have a few functions that i want several classes to all use. but because all the classes are linked in some way it always says these functions are already defined.

--------------------------
globals.h
somefunction();
---------------------------
CObject.h
#include "globas.h"
class CObject
{
};
-------------------------
CBullet.h
#include "CObject.h"
#include "globals.h"
class CBullet : public CObject
{
};
---------------------------
CPlayer.h
#include "CObject.h"
#include "globals.h"
class CPlayer : public CObject
{
};

main.cpp
#include "CObject.h"
#nclude "CBullet.h"
#include "CPlayer,h"
#include "globas.h"

i can get the inheritance to work but i want the classes to use stuff from the globals like constants and functions .
normally i would just stick all the classes and my globals in my main cpp but thats not easy to sort my code out when i have problems or need to change it.

many thanks in advance :)
Advertisement
You need to use include guards.

In each header file you have, do this:


// MyHeader.h
#ifndef _MYHEADER_H_
#define _MYHEADER_H_

// code

#endif


With that, you can #include the file in any number of other files, and it will only actually be included once, preventing multiple definitions.

_MYHEADER_H_ can be any unique name. You should generally use some consistant syntax based on the name of the file.

More info about the technique.

[font=arial,helvetica,sans-serif]_MYHEADER_H_ is a reserved symbol, as it begins with an underscore, then a capital. [color=#000000]Just use [color=#000000]MYHEADER_H if you're going to use include guards based off the file name.[/font]



[font=arial,helvetica,sans-serif][color=#000000]Or, don't bother coming up with unique identifiers and just use #pragma once. It's supported on both gcc and msvc.[/font]



[font=arial,helvetica,sans-serif]_MYHEADER_H_ is a reserved symbol, as it begins with an underscore, then a capital. [color=#000000]Just use [color=#000000]MYHEADER_H if you're going to use include guards based off the file name.[/font]




Doh, got me there.


[font=arial,helvetica,sans-serif][color=#000000]Or, don't bother coming up with unique identifiers and just use #pragma once. It's supported on both gcc and msvc.[/font]




If you have the same file in different locations, #pragma once will treat them as different files. This can happen with certain build systems which copy files around. An edge case to be sure though.
hi guys thanks for the replies.

i have tried both of these ways but it still gives the same errors i changed _COBJECT_ to COBJECT_ ect. is the problem where i am including them i mean should i include them in the .h or .cpp files?

i find that if i dont include it in my main.cpp then i dont get the error( although i get lots of other errors which are caused by not including globals.h) but i need it in main any ideas

thanks again guys :)

i have tried both of these ways but it still gives the same errors i changed _COBJECT_ to COBJECT_ ect. is the problem where i am including them i mean should i include them in the .h or .cpp files?


You should _closely_ reread the very first answer.
f@dzhttp://festini.device-zero.de
ok i have reread the first reply and have tried to change all of my names and even tried #pragma once.

still no joy though it must be something im doing i mean i know it works as they all include SDL files and they dont conflict.



CObject.h
#ifndef _OBject_
#define _OBject_
#include "globals.h"

#endif


CObject.h
#include "globals.h"
#ifndef _OBject_
#define _OBject_

#endif

CObject.h
#ifndef OBject_
#define OBject_
#include "globals.h"

#endif


CObject.h
#include "globals.h"
#ifndef OBject_
#define OBject_

#endif


CObject.h
#pragma once
#include "globals.h"

CObject.h
#include "globals.h"
#pragma once


i have 3 classes a globals.h and a main so i have 4 .h files and 4.cpp files i have tried to change each one as per the above example and each time i still get the multiple definitions i only get problems with the "globals.h"

where should i put the includes? the header files for my classes dont need to know about the globals but the .cpp's do.

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?


many thanks again smile.png
yes, you should split the definition and the declation of the globals.
If not, they will be defined in every cpp where you include the header file. (leading to redefinition errors)

It's usually a good idea to include header files only in the .cpp, unless you really have to include it in the header. (to not pollute the user of the header file with unnecessary dependencies).
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).
i am sorry for a trivial response below but i must of posted this as you posted your reply i am at work so i am slowly typing the replies.

that is a very complete and concise reply and i can see how it is perfectly correct :) thank you for your help not only in fixing my problem but in increasing my understanding and helping me to become a better programmer. as now i can have a project that has many files and not every thing crammed in one main.cpp

i had come across include guard and pragma once before and tried to use them but now i know how to do it properly i dont think i will have any problems anymore:) well not with #include's


thank you for your help it is much appreciated


EDIT: To Reply to rip-off the below reply was for Olof Hedman

Ah ok cool i will try that later thanks for the help smile.png

does that mean that i should put global variables in the .cpp
globals.h

void myFunction();


globals.cpp

int myInt;
const int myOtherInt = 1;
void myfunction()
{
//do stuff
}

This topic is closed to new replies.

Advertisement