PDA

View Full Version : help ! header file inclusion strategies


relief7
05-20-2007, 04:51 AM
I would like to hear your opinions on what is the best strategy for inclusion of header files. Do you usually put your includes in the .h files or in the .cpp files ?

I used the first approach for a project but I ran into a problem with circular dependencies. It goes like this:

-Compile I.cpp
-I.cpp contains #include "I.h"
(class I is declared in I.h)
-I.h contains #include "S.h"
-S.h contains #include "V.h"
-V.h contains #include "I.h" and
class V : public I
{
}

But because of the header guards (ifdef etc.) I.h is not included again in file V.h so class V can not find its base class. Now what I do not understand...I tried to put a forward declaration "class I" directly in front of the declaration of V but it does not help. It still can not find the base class. Does anybody know what I am doing wrong ?

Now I found this article (http://www.eventhelix.com/RealtimeMantra/HeaderFileIncludePatterns.htm) which suggests to use includes only in .cpp files and use as much forward declarations in headers as possible because it compiles faster and results in less clutter. As I dont have any experience with real large scale projects I would like to ask you about your opinion. Is this the way large projects are handled ?

relief7
05-20-2007, 05:28 AM
Ok, I just found out that if V.h contains the following

class V
{
I * i;
};


instead of the inheritance then it compiles without errors. So I guess forward declarations are not sufficient if you want to inherit from that class because the compiler needs to know the size of I and what other variables / objects it contains, right ?

But still how can I fix the problem of the inheritance without rearranging the includes into the cpp files ?

playmesumch00ns
05-20-2007, 12:00 PM
I'm having trouble getting my head round your exact inhertiance pattern but basically your design is screwed if you're having a circular dependency like that. Why does S.h need to include V.h?

As a general rule, only include header files in .cpp files as much as possible.

And yes, your second method works because the compiler knows what size an I* is already, but without the full declaration of I, does not know what size an I is. Swap the I* for an I instance and the compile will break again for this reason.

Header files issues should definitely not be forcing your decisions on whether to use inheritance or composition.

UrbanFuturistic
05-20-2007, 03:13 PM
Really, as much as is possible, header files should only include EXTERNs with the class variables and functions being contained in an external .cpp file that is either shared (as a .so or .dll) or statically linked at compile time.

The main reason this is considered to 'compile' faster is actually because you are only compiling those parts that you need to each time the project is redone with everything linked together at the end. For example: you have matrixmath.cpp, imageload.cpp, mainloop.cpp and main.cpp and unless you change something in more than one file only one of those files will need to be recompiled when you go to test your changes as a recompile of the other files would yield the exact same result as before and is redundant. When the compiler is finished with the recompiling (it will assume all the EXTERNs are correct) the linker plugs all the separate parts together so long as you have told it which parts are needed or, in the case of shared object files, it assumes the correct files will be available at runtime.

Other than that, you may have to put up some of the offending code before anyone can really help you. It might be as simple as a type in an ifdef or whathaveyou.

relief7
05-20-2007, 07:25 PM
Thank you for your quick replies and your opinions. It is much appreciated ! :) I see one never stops learning about c++. But that is the beauty of it, isn't it ?

Ok I resolved all problems now that I rearranged all the includes by using forward declarations in the header files and having most of the includes in the .cpp files. It works much better !

playmesumch00ns: It is not necessary to get behind the relationship by my wacky description. :) It's a little bit tricky and it had to be like that. I guess you could describe it as a cyclic dependency of header files with inheritance. But you are right, when I make it an instance, it does not compile either. I did not know that c++ does not allow forward declared classes as base classes. So making class I a pointer in class V was just a test if it compiles and did not affect the way I arrange the classes. At least I know now that it is common practice to use headers mainly in .cpp files. Because at first, I thought there is usually one include in the cpp file (e.g. I.cpp contains #include "I.h", a header with the same name) and everything else needed is included in this header. Thanks for clearing this up !

odubtaig: Thanks for your explanation but I think I do not quite understand what you wrote. I neither use variables declared as extern nor did I say that I include .cpp files if that is what you mean. It was just a chain of header file includes that resulted in a cyclic dependency not resolvable by a forward declaration. But as I said before, I fixed it so I won't bother you with complex code anymore ! :scream:


But please allow me one more question concerning this strategy of header file inclusion (in the cpp files). Lets say I have the following files (simplified, no header guards etc.)

A.h
// A.h
class A
{
B b;
...
};

B.h
// B.h
class B
{
...
};

x.cpp
// x.cpp
#include "B.h"
#include "A.h"

void someMethod ( void )
{
A a;
a.doSomething ( )
}

I assume it is correct that A.h does not need the include of B.h because the cpp files take care of it when being compiled. So in x.cpp, additionally to the inclusion of A.h it is necessary to include B.h before that, so B is known to A when A is defined ? In the cpp file we only know about class A because we use it but we also need to know which other classes A refers to and include the necessary files ?

I worked on another project where the project was organized like this and everytime we wanted to use one class in a cpp file we had to include a whole cascade of other files that this class refered. So I am wondering, when following the strategy of having #includes in the .h files, this cascade is implicitly done by the compiler by recursively following each of the includes and for the other strategy (#includes in the .cpp files) you yourself have to explicitly type all the includes (also cascaded ones like in the case of A and B above) that are needed by every class you refer to in the cpp file and all the other classes that are referred to by the classes you refer to etc.. OMG, what a sentence, LOL.

And consider the case where A does not contain an object of B anymore. Then you have to take care of that in your cpp file too by erasing the include of B.h or basically in every cpp file that refers "A.h".

In the first strategy I named you would simply delete the #include in the header file but in this approach you would have to look through every cpp file and erase the corresponding line ? I am still not convinced that this strategy really decreases clutter as you yourself have to take care of the includes in the cpp files a lot more.

Though I am convinced that it compiles faster, you have more control and that you can resolve dependencies a lot better. But I do not see where it is supposed to decrease clutter. I can imagine that big projects need a lot of care when following this approach. So do you always look through your code when a composition object in one class is deleted to get rid of unnecessary inclusions in cpp files ? I mean we all know that an additional inclusion does make no harm in most cases but it increases compile time. And I think that if it is not looked after very well, you do not have an increase of compile speed compared to the other approach. Furthermore, it takes time to refactor and always have inclusions in cpp files up-to-date. Any thoughts ? Is the best way to do it maybe a way in between where you could have the best of both worlds ? For example, common includes in the header files, other includes in the cpp files to resolve tricky dependencies ?

Sorry for the long post but again... I have not a lot of experience in large-scale projects so your opinion is really appreciated ! I think this is one of many fundamental aspects of architecture/coding standards and I just want to make sure that I am following the most practical approach and doing it right the first time.

playmesumch00ns
05-21-2007, 12:53 PM
A.h should include B.h because A needs B's declaration in order to be able to be declared.

gga
05-21-2007, 09:44 PM
The following should solve any cycle dependencies and compile the fastest.


B.h
class B {
public:
// ...methods...
};


A.h


// declaration of B as a class type.
// Cannot be used, but can be stored/passed as ptr or reference.
class B;

class A {
B* _b;
public:
// ...methods...
~A(); // important - this should clean _b
};

// no A function here should operate on _b.



A.cpp


#include "B.h"

// add all funcs that operate on _b.

// clear b from A instance..
A::~A() {
delete _b;
}


other.h

#include "A.h"
// #include "B.h" only needed if you operate on B here in some function

void someBfunc( const B& );
void someAfunc( const A& );


other.cpp

#include "B.h"

void someBfunc( const B& ) { ... }
void someAfunc( const A& ) { ... }

CGTalk Moderation
05-21-2007, 09:44 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.