Jonathan Livni
Jonathan Livni

Reputation: 107082

Where should #include statements reside?

As a returning newbie to C++, I'm trying to sort the #include methodology.

I'm following a certain set of guidelines I detail below the following example. So far this has worked out for me (the entire project keeps compiling :) ), but I'm worried I may encounter problems in the future, therefore my questions are - is this a correct methodology? Is there a better one? What's the underlying logic that explains it?

Consider the following example:

Father.h

#pragma once
class Father
{
    // Some implementation
};

ClassA.h

#pragma once
#include "Father.h"
#include "StructC.h"
class ClassB;
class ClassA : public Father
{
    StructC struct_c_obj;
    ClassB class_b_obj;
    // Some implementation
};

ClassA.cpp

#include "Father.h"
#include "ClassB.h"
#include "StructC.h"
// Some implementation

ClassB.h and ClassB.cpp
A class without includes

StructC.h

struct StructC {
    // Some implementation
};

I follow these guidelines:

This is probably a clumsy set of guidelines with little understanding of the underlying logic, so I'm probably going to get some wrath... Bring it on, I am trying to learn here... :)

UPDATES:

Upvotes: 4

Views: 439

Answers (5)

icecrime
icecrime

Reputation: 76745

These are the guidelines I personally follow :

  • Prefer forward declarations instead of includes whenever possible. In your case, ClassA contains a ClassB so a #include "ClassB.h" is required. Had the ClassB type only appear in the file by pointer or reference, a forward reference would have been sufficient
  • Make header file "self sufficient" : compilation should never depend on the order of inclusions, and an include file should include / forward declare all it needs to be parsed
  • To ensure that the preceding guideline is respected, always include ClassA.h first in ClassA.cpp, and use an arbitrary ordering for the following includes (I'm using alphabetical sort)

Regarding other aspects :

  • #pragma is non standard, prefer include guards
  • Keep in mind that you should never forward declare standard types : if std::string appears in your header file, you have to #include <string>
  • If you end up with a header file which includes a million other files, you might want to look into the pimpl idiom to reduce dependencies (this article also contains several other guidelines regarding header files).

Upvotes: 9

lijie
lijie

Reputation: 4871

#pragma once is non-standard (but widely supported), so you may/may not want to use #ifdef guards instead.

As for whether you need to #include any particular header, it depends. If the code only requires a forward declaration, by all means avoid the import by just forward declaring the type.

And with the exception of template stuff, I think it is probably not-too-pretty to place long function definitions in the header files.

Having said that, I think that ClassA.h should actually include ClassB.h because any user of ClassA.h (presumably to use ClassA) will have to have ClassB.h. Well, if it is doing anything like allocating it.

Upvotes: 1

Henrik
Henrik

Reputation: 23324

Don't use forward declaration of ClassB, when ClassA has a data member of this type. It's OK to use it, when it has a pointers to ClassB, as in:

#pragma once 
#include "Father.h" 
#include "StructC.h" 
class ClassB; 
class ClassA : public Father 
{ 
    StructC struct_c_obj; 
    ClassB *class_b_obj; 
    // Some implementation 
}; 

Upvotes: 1

Simone
Simone

Reputation: 11797

I usually don't use pragma once because pragmas are not standad. You could have to port your code to a different compiler where it's not defined, and you'd have to rewrite each with #ifndef ... #define idiom.

This is because I go straight with #ifndef ... #define.

Second thing: using many includes in an header file is not a good idea: I always try to minimize them. If you got too much of them, each time you change a little thing in one of them you'll have to recompile each dependent .cpp file.

If that's the case, I adopt the Pimpl idiom, that you can find described here (see the C++ example). Anyway, if the project's size is not that big, I think that your approach is correct.

Upvotes: 0

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798486

One thing I've garnered from Python (because it's an absolute requirement there) is "import (include) it in the modules where you use it". This will keep you out of trouble when it comes to having or not having the definitions around.

Upvotes: 0

Related Questions