Sign in to follow this  

Include problems

This topic is 2085 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.
[code]
--------------------------
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"
[/code]
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 :)

Share this post


Link to post
Share on other sites
You need to use [i]include guards.[/i]

In each header file you have, do this:

[code]
// MyHeader.h
#ifndef _MYHEADER_H_
#define _MYHEADER_H_

// code

#endif
[/code]

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.

[url="http://www.google.com/#hl=en&sclient=psy-ab&q=c%2B%2B+include+guard&oq=c%2B%2B+include+guard&aq=f&aqi=g2g-v1g-q1&aql=&gs_l=hp.3..0l2j0i15j0i22.5441045l5445475l0l5445975l12l10l0l1l1l0l739l1577l7j3-1j6-1l10l0.frgbld.&pbx=1&bav=on.2,or.r_gc.r_pw.r_qf.,cf.osb&fp=349eda12779a3fe1&biw=1920&bih=996"]More info about the technique.[/url]

Share this post


Link to post
Share on other sites
[left][size=3][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][color=#000000]MYHEADER_H if you're going to use include guards based off the file name.[/color][/font][/size][/left]

[left][size=3][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.[/color][/font][/size][/left]

Share this post


Link to post
Share on other sites
[quote name='Slavik81' timestamp='1333403267' post='4927653']

[left][size=3][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][color=#000000]MYHEADER_H if you're going to use include guards based off the file name.[/color][/font][/size][/left]
[/quote]

Doh, got me there.

[quote name='Slavik81' timestamp='1333403267' post='4927653']
[left][size=3][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.[/color][/font][/size][/left]
[/quote]

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.

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
[quote name='thestien' timestamp='1333430504' post='4927780']
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?
[/quote]

You should _closely_ reread the very first answer.

Share this post


Link to post
Share on other sites
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.

[code]

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
[/code]

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 [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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
[code]
#ifndef GLOBALS_H
#define GLOBALS_H

void someFunction(/* ... */);

#endif
[/code]

globals.cpp
[code]
#include "globals.h"

void someFunction(/* ... */) {
// ...
}
[/code]

object.h
[code]
#ifndef OBJECT_H
#define OBJECT_H

class Object
{
public:
virtual ~Object();
virtual void frobnicate() = 0;
// ...
};

#endif
[/code]

object.cpp
[code]
#include "object.h"

Object::~Object()
{
}
[/code]

bullet.h
[code]
#ifndef BULLET_H
#define BULLET_H

#include "object.h"

class Bullet : public Object
{
public:
virtual void frobnicate();
};

#endif
[/code]

bullet.cpp
[code]
include "bullet.h"

#include "globals.h"

void Bullet::frobnicate()
{
// ...
someFunction(/* ... *);
// ...
}
[/code]

main.cpp
[code]
#include "bullet.h"

int main()
{
Bullet bullet;
bullet.frobnicate();
}
[/code]
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).

[quote]
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 [i]would compile[/i] 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).

Share this post


Link to post
Share on other sites
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 [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

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

void myFunction();


globals.cpp

int myInt;
const int myOtherInt = 1;
void myfunction()
{
//do stuff
}
[/code] Edited by thestien

Share this post


Link to post
Share on other sites
Yes, global variables must not be defined in the header file itself.

Some values that are "const" can appear in header files (integral values, I believe). Technically, these are implicitly "static", which means that each translation unit gets its own copy, and they aren't considered to be part of the list of objects for import/export. So "myOtherInt" could appear in globals.h.

If you need to have access to a global variable in different source files (e.g. myInt in your example), one way is to declare it as "extern" in the header file. Then, in exactly one source file, define it. Another way is to expose function for manipulating, accessing, or setting the value, depending on which is necessary.

However, generally global data is considered poor design, it is preferred to pass such data as a parameter, or for a class to store some kind of reference to it in a member.

Note finally that even though global variables are zeroed if not explicitly given a value, it is a good idea to include a value anyway. This shows that you didn't just forget to include a value. It also makes it clear that this is intended to be a definition and not a declaration.

Share this post


Link to post
Share on other sites
[quote name='rip-off' timestamp='1333450144' post='4927837']
Some values that are "const" can appear in header files (integral values, I believe). Technically, these are implicitly "static", which means that each translation unit gets its own copy, and they aren't considered to be part of the list of objects for import/export. So "myOtherInt" could appear in globals.h.
[/quote]
Integral values aren't treated specially by const. Any const variable has implicit internal linkage and can therefore be placed in a header without generating duplicate symbol linker errors. However, it will still be the case for all types that each source file that includes that header will have a separate copy of that variable. For integral and other primitive types the compiler and linker will often be smart enough to be able to get rid of excess copies. For more complex types they often won't be.

Share this post


Link to post
Share on other sites

This topic is 2085 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this