University of Leeds

Header Guards

Introduction

Consider the following classes.

"Person.h"

1
2
3
4
5
6
#include <string>

class Person {
 public:
  std::string name;
};

Here we simply have a C++ string that is used to store the name of a person. The string class is part of the C++ standard library.

"Parents.h":

1
2
3
4
5
6
7
#include "Person.h"

class Parents {
 public:
  Person father;
  Person mother;
};

This class is used to store a set of parents. Since a parent is a person, we use the Person class to represent each parent (meaning we can set their name). We may then use these classes in our main.cpp file.

"main.cpp"

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include "Parents.h"
#include "Person.h"
#include <iostream>

int main() {
  Person best_friend;
  best_friend.name = "John";
  std::cout << "My best friend is " << best_friend.name << ".\n";

  Parents my_parents;
  my_parents.father.name = "William";
  my_parents.mother.name = "Susan";

  std::cout << "My parents are called " << my_parents.father.name << " and "
            << my_parents.mother.name << ".\n";
  return 0;
}

This code simply creates a Person object used to hold the details of our best friend and also creates an instance of the Parents class to hold details of our parents. Note that we must include the header files of each class in order to use them in main.cpp.

Compilation error

Although everything looks reasonable enough, this code will not compile and we get the following compiler error (exact message may vary depending on which compiler was used).

1
2
3
4
5
6
7
8
9
In file included from main.cpp:2:
Person.h:6:7: error: redefinition of 'class Person'
 class Person {
       ^~~~~~
In file included from Parents.h:6,
                 from main.cpp:1:
Person.h:6:7: note: previous definition of 'class Person'
 class Person {
       ^~~~~~

Looking at the error message, it seems to suggest that our Person class has been defined more than once. How has this happened?

#include pre-processor directive

The #include pre-processor directive essentially copies in the contents of the file that we are including. Once the pre-processor has run, our main.cpp will look something like below.

main.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <string>

class Person {
public:
  std::string name;
};

class Parents {
public:
  Person father;
  Person mother;
};

#include <string>

class Person {
public:
  std::string name;
};

#include <iostream>

int main() {
  Person best_friend;
  best_friend.name = "John";
  std::cout << "My best friend is " << best_friend.name << ".\n";

  Parents my_parents;
  my_parents.father.name = "William";
  my_parents.mother.name = "Susan";

  std::cout << "My parents are called " << my_parents.father.name << " and "
  << my_parents.mother.name << ".\n";
  return 0;
}

Since both main.cpp and Parents.h include our Person class, we can see that the definition of our Person class now appears twice! This is the cause of the compilation error. So how do we fix it?

Header guards

We can use header guards in header files to prevent them being included multiple times.

"Person.h"

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#ifndef PERSON_H
#define PERSON_H

#include <string>

class Person {
 public:
  std::string name;
};

#endif // PERSON_H

"Parents.h"

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#ifndef PARENTS_H
#define PARENTS_H

#include "Person.h"

class Parents {
 public:
  Person father;
  Person mother;
};

#endif // PARENTS_H

The #ifndef pre-processor directive checks to see if a token has not already been defined in the code. If it has not, then the token is defined and the code between #ifndef and #endif will be included. If it has already been defined (i.e. the header has already been included elsewhere), then it is skipped and the code will not be included again. This prevents the header from appearing more than once. Note that the naming convention of the token is the file name in upper-case with an underscore instead of a full-stop and that an in-line comment is often used after #endif to remind us which #ifndef token we are closing.

Summary

After including header guards in our header files, the code will compile successfully. When the code runs, we will see the following output in the terminal.

My best friend is John.

My parents are called William and Susan.

In summary, always use header guards!