Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • All *.h are headed by a #pragma once declaration
  • If ClassA inherits from class Father, it must include it in both *.h and *.cpp file
  • If ClassA uses ClassB (and has a ClassB variable declared at the class's scope), it has a class ClassB; decleration in ClassA.h and an #include "ClassB.h" in ClassA.cpp
  • If ClassA uses StructC (and has a StructC variable declared at the class's scope), it has to include it in both ClassA.h and ClassA.cpp
  • If ClassA uses ClassD or StructE but only in the ClassA.cpp file, then it should include them only there

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:

  • As some have written below, I have an error in the example - you can use a forward declaration of ClassB in ClassA only if ClassA has a pointer or a reference to ClassB and not if it has a simple ClassB data-member.
like image 252
Jonathan Livni Avatar asked Dec 22 '22 20:12

Jonathan Livni


2 Answers

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).
like image 182
icecrime Avatar answered Dec 31 '22 01:12

icecrime


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 
}; 
like image 40
Henrik Avatar answered Dec 31 '22 02:12

Henrik