2.8 — Programs with multiple code files

Adding files to your project

As programs get larger, it is common to split them into multiple files for organizational or reusability purposes. One advantage of working with an IDE is that they make working with multiple files much easier. You already know how to create and compile single-file projects. Adding new files to existing projects is very easy.

Best practice

When you add new code files to your project, give them a .cpp extension.

For Visual Studio users

In Visual Studio, right click on the Source Files folder (or the project name) in the Solution Explorer window, and choose Add > New Item….

Make sure you have C++ File (.cpp) selected. Give the new file a name, and it will be added to your project.

Note: Your Visual Studio may opt to show you a compact view instead of the full view shown above. You can either use the compact view, or click “Show all Templates” to get to the full view.

Note: If you create a new file from the File menu instead of from your project in the Solution Explorer, the new file won’t be added to your project automatically. You’ll have to add it to the project manually. To do so, right click on Source Files in the Solution Explorer, choose Add > Existing Item, and then select your file.

Now when you compile your program, you should see the compiler list the name of your file as it compiles it.

For Code::Blocks users

In Code::Blocks, go to the File menu and choose New > File….

In the New from template dialog, select C/C++ source and click Go.

You may or may not see a welcome to the C/C++ source file wizard dialog at this point. If you do, click Next.

On the next page of the wizard, select “C++” and click Next.

Now give the new file a name (don’t forget the .cpp extension), and click the All button to ensure all build targets are selected. Finally, select finish.

Now when you compile your program, you should see the compiler list the name of your file as it compiles it.

For gcc users

From the command line, you can create the additional file yourself, using your favorite editor, and give it a name. When you compile your program, you’ll need to include all of the relevant code files on the compile line. For example: g++ main.cpp add.cpp -o main, where main.cpp and add.cpp are the names of your code files, and main is the name of the output file.

For VS Code users

To create a new file, choose View > Explorer from the top nav to open the Explorer pane, and then click the New File icon to the right of the project name. Alternately, choose File > New File from the top nav. Then give your new file a name (don’t forget the .cpp extension). If the file appears inside the .vscode folder, drag it up one level to the project folder.

Next open the tasks.json file, and find the line "${file}",.

You have two options here:

  • If you wish to be explicit about what files get compiled, replace "${file}", with the name of each file you wish to compile, one per line, like this:

"main.cpp",
"add.cpp",

  • Reader “geo” reports that you can have VS Code automatically compile all .cpp files in the directory by replacing "${file}", with "${fileDirname}\\**.cpp" (on Windows).
  • Reader “Orb” reports that "${fileDirname}/**.cpp" works on Unix.

A multi-file example

In lesson 2.7 -- Forward declarations and definitions, we took a look at a single-file program that wouldn’t compile:

#include <iostream>

int main()
{
    std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n';
    return 0;
}

int add(int x, int y)
{
    return x + y;
}

When the compiler reaches the function call to add on line 5 of main, it doesn’t know what add is, because we haven’t defined add until line 9! Our solution to this was to either reorder the functions (placing add first) or use a forward declaration for add.

Now let’s take a look at a similar multi-file program:

add.cpp:

int add(int x, int y)
{
    return x + y;
}

main.cpp:

#include <iostream>

int main()
{
    std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n'; // compile error
    return 0;
}

Your compiler may compile either add.cpp or main.cpp first. Either way, main.cpp will fail to compile, giving the same compiler error as the previous example:

main.cpp(5) : error C3861: 'add': identifier not found

The reason is exactly the same as well: when the compiler reaches line 5 of main.cpp, it doesn’t know what identifier add is.

Remember, the compiler compiles each file individually. It does not know about the contents of other code files, or remember anything it has seen from previously compiled code files. So even though the compiler may have seen the definition of function add previously (if it compiled add.cpp first), it doesn’t remember.

This limited visibility and short memory is intentional, for a few reasons:

  1. It allows the source files of a project to be compiled in any order.
  2. When we change a source file, only that source file needs to be recompiled.
  3. It reduces the possibility of naming conflicts between identifiers in different files.

We’ll explore what happens when names do conflict in the next lesson (2.9 -- Naming collisions and an introduction to namespaces).

Our options for a solution here are the same as before: place the definition of function add before function main, or satisfy the compiler with a forward declaration. In this case, because function add is in another file, the reordering option isn’t possible.

The solution here is to use a forward declaration:

main.cpp (with forward declaration):

#include <iostream>

int add(int x, int y); // needed so main.cpp knows that add() is a function defined elsewhere

int main()
{
    std::cout << "The sum of 3 and 4 is: " << add(3, 4) << '\n';
    return 0;
}

add.cpp (stays the same):

int add(int x, int y)
{
    return x + y;
}

Now, when the compiler is compiling main.cpp, it will know what identifier add is and be satisfied. The linker will connect the function call to add in main.cpp to the definition of function add in add.cpp.

Using this method, we can give files access to functions that live in another file.

Try compiling add.cpp and the main.cpp with the forward declaration for yourself. If you get a linker error, make sure you’ve added add.cpp to your project or compilation line properly.

Tip