News & UpdatesProgrammingWeb programming StoreMy Projects
Links
Affiliates

C++ Tutorial – 29 – Headers

When a project grows it is common to split the code up into different source files. When this happens the interface and implementation are generally separated. The interface is placed in a header file, which commonly has the same name as the source file and a .h file extension. This header file contains forward declarations for the source file entities that need to be accessible to other files in the project.

Why to use headers

C++ requires everything to be declared before it can be used. It is not enough to simply compile the source files in the same project. For example, if a function is placed in MyFunc.cpp, and a second file named MyApp.cpp in the same project tries to call it, the compiler will report that it cannot find the function.

// MyFunc.cpp
void myFunc() 
{ 
  // …
}
 
// MyApp.cpp
int main()
{
  myFunc(); // error: myFunc identifier not found
}

To make this work the function’s prototype has to be included in MyApp.cpp.

// MyApp.cpp
void myFunc(); // prototype
 
int main()
{
  myFunc(); // ok
}

Using headers

This can be made more convenient if the prototype is placed in a header file named MyFunc.h and this header is included in MyApp.cpp through the use of the #include directive. This way if any changes are made to MyFunc there is no need to update the prototypes in MyApp.cpp. Furthermore, any source file that wants to use the shared code in MyFunc can just include this one header.

// MyFunc.h
void myFunc(); // prototype
 
// MyApp.cpp
#include "MyFunc.h"

What to include in headers

As far as the compiler is concerned there is no difference between a header file and a source file. The distinction is only conceptual. The key idea is that the header should contain the interface of the implementation file – that is, the code that other source files will need to use. This may include shared constants and macros.

// MyApp.h - Interface
#define PI 3.14
const double E = 2.72;

The header can also contain prototypes of the shared functions defined in the source file.

void myFunc();

Additionally, shared classes are typically defined in the header, while their methods are implemented in the source file.

// MyApp.h
class MyClass 
{
 public:
  void myMethod();
};
 
// MyApp.cpp
void MyClass::myMethod() {}

The header should not include any executable statements, with two important exceptions. First, if a shared class member function or global function is declared as inline, that function must be defined in the header. Otherwise, calling the inline function from another source file will give an unresolved external error.

// MyApp.h
inline void myFunc() {}
 
class MyClass 
{
 public:
  void myMethod() {}
};

The second exception is shared templates. Since templates are not compiled until they are required, the implementation of a shared class or function template must be in the header file together with its declaration.

template<class T>
void templateFunction()
{
  // …
}

Include guards

An important thing to bear in mind when using header files is that a code entity may only be defined once in every source file. Consequently, including the same header file more than once will most likely result in compilation errors. To avoid this problem of multiple definitions, a couple of preprocessor directives can be used to create a so called include guard. An include guard is created by enclosing the start of the header in a #ifndef section that checks for a macro specific to that header file. Only when the macro is not defined is the file included. The macro is then defined, which effectively prevents the file from being included again.

// MyApp.h
#ifndef MYAPP
#define MYAPP
// …
#endif
Recommended additional reading:
Sams - Teach Yourself C++ in One Hour a Day