C++ Include Directive

Learn how we can split our code into multiple files, to keep everything organised. Then, use the include directive to automatically bring them back together for compilation.
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

3D art showing a character on a desert planet
Ryan McCombe
Ryan McCombe
Posted

In the previous lesson, we introduced the preprocessor, and how we can use it to conditionally remove parts of our code before we send it off for compilation.

The second aspect of the preprocessor that we're looking at essentially does the opposite. It give us a way to add additional code to our files.

This can be done using the #include directive. You may have noticed we've already been using an include directive this whole time:

#include <iostream>

We can finally explain what that line is doing!

When we build our project, the preprocessor will see this include directive, and it will replace it with a load of code that is stored in a different file.

With the #include <iostream> instruction specifically, it adds all the code that we've been using to log out to the console. This includes things like cout and endl.

More generally, the #include directive unlocks the ability for us to split our code into multiple files. This is vital for organising non-trivial projects.

With our project seperated into multiple files, we can then use the #include directive any time the code in one file needs to use something in one of our other files.

Commonly, this will be our classes. We can, for example, have the code for our Character class in a different file, such as Character.cpp, and still create Characters in our main.cpp file, as long as we use #include properly:

// Character.cpp
class Character {};
// main.cpp
#include <iostream>
#include "Character.cpp"

int main() {
  Character PlayerCharacter;
}

Once the preprocessor encounters #include "Character.cpp" in our main.cpp, it will jump into action and replace that directive with the contains of our Character.cpp file.

Because of this, the code that our compiler receives will be this:

// main.cpp
#include <iostream>
class Character {};

int main() {
  Character PlayerCharacter;
}

This file now looks very similar to what we've seen in the past. Now, however, instead of having to work with a main.cpp that constantly gets bigger, we're able to organise our project into multiple files, each of them much easier to work with.

Something might be immediately apparent here: when including <iostream> we wrapped it in chevrons - < and > whilst, when we included "Character.cpp" we used double quotes.

The difference in syntax is essentially telling the compiler where to look for the files we're trying to include.

C++ Include Directories - Where does #include look for files?

When we use the < and > syntax, we are letting our tools decide where to look for the requested file. This is covered in more detail in the _Setting Include Directories section below.

The other way we can use the directive is with double quotes " , ie, #include "SomeFile.cpp". The behavior of this approach is that the preprocessor will look in the directory of the requesting file.

For example, if we had this directive in main.cpp, the preprocessor would look in the folder where main.cpp is located, to see if it can find a file called SomeFile.cpp.

If it can't, it will fall back to the checking the locations defined by the compiler or the IDE.

This means that, whether we use <> or "", the preprocessor will probably be able to find the file we need. The difference is mostly just convention.

Typically the "" form would indicate we are trying to import a file we created, or a file we added to our project directly.

On the other hand, the < and > notation often indicates we are trying to import something from a library - often the C++ Standard Library.

The standard library is a collection of generally useful code - such as iostream - that ships alongside C++.

By being separate to the language, we can #include only the parts of the standard library that we need, keeping unnecessary bloat out of our software.

We'll cover the standard library more in later chapters.

Including C++ Files in Different Directories

Not all the files we will want to #include will be in the same directory as the file we're adding the #include directive to.

To solve this, we can add path traversal to our #include directives, as shown below. These paths are relative to the file where the #include directive is beign used.

// Look in the same directory as the current file
#include "Math.cpp"

// Look in a directory called Helpers, in the same directory as the current file
#include "Helpers/Math.cpp"

// Traverse up a level to look in the parent directory of the current file
#include "../Math.cpp"

// Traverse up two levels, and then into a directory called Helpers
#include "../../Helpers/Math.cpp"

Test your Knowledge

How can we use the preprocessor to include the content from a file in the same directory called Utilities.cpp?

How can we use the preprocessor to include the content from the parent directory called Utilities.cpp?

Setting C++ Include Directories

In the previous section, we discussed how our tools (eg, the IDE) would control where the preprocessor looks for files referenced by the #include directive.

Most of the time, our IDEs will set sensible default values for this. However, they will also let us add or modify these locations. In Visual Studio, this is under Project Settings > C/C++ > Include Directories

This is quite useful as, if we have a directory we import from frequently, we can add that to our project settings.

This can make our lives easier, and simplify our #include directives greatly. We could go from something like this:

#include "../../Math.cpp"
#include "../../../Shared/Static/Physics.cpp"

To something much simpler:

#include "Math.cpp"
#include "Physics.cpp"

This also makes our projects easier to re-organise. Any time we try to update our directory structure, we could potentially have to update dozens of relative #include directives. Instead, if the path is defined in the include directories, we would only have to update it in that one place.

A Note on C++20 Modules

When we use the #include directive, we can literally think of it as copying and pasting the contents of a file into another file. This is quite a crude operation, and it has some issues we need to manage.

The next two lessons will focus on two techniques that have evolved to ensure the amalgamation of code still works how we expect.

However, the C++20 standard, published in December 2020, introduced a new feature to the language called modules. They use the C++ import syntax, rather than the preprocessor's #include.

// Before
#include "Character.cpp"

// After
import Character;

We cover modules in more depth on the intermediate course.

Modules will will supersede #include directives eventually. However, things move slowly in the C++ world. As of 2022, few compilers fully support the new standard yet and, even once they do, #include will still be more common for many years to come.

Therefore, for now, it's more important to understand how the #include directive works.

Was this lesson useful?

Ryan McCombe
Ryan McCombe
Posted
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

The Preprocessor and the Linker
3D art showing a progammer setting up a development environment
This lesson is part of the course:

Intro to C++ Programming

Become a software engineer with C++. Starting from the basics, we guide you step by step along the way

Free, unlimited access!

This course includes:

  • 66 Lessons
  • Over 200 Quiz Questions
  • Capstone Project
  • Regularly Updated
  • Help and FAQ
Next Lesson

C++ Include Conflicts and #pragma once

An introduction to a big problem with the include directive, and two different methods ways to work around it.
3D art showing a mechanic character
Contact|Privacy Policy|Terms of Use
Copyright © 2023 - All Rights Reserved