Home CPSC 340

Using Multiple Files

Overview

When writing larger programs, it becomes impractical to put all of the code in one file. Instead, we split the code into multiple files where the code in a single file is logically related.

This also allows parts of programs to be reused in multiple other programs.

When using multiple files, we still need to make sure that everything is declared before it is used.


Declarations vs. Definitions

In C++, there is a difference between the declaration of a function and the definition.

Functions must be declared before they are used, but they do not need to be defined before they are used. When writing programs with multiple files, the declarations and definitions of a function are separated.


Member Function Definitions

When using classes, separating the declaration and definition is slightly trickier. Consider the Circle class below:


class Circle {
  public:
    void setRadius(double r) {
      radius = r;
    }

    double getArea( ) {
      return PI * radius * radius;
    }

    double getCircumference( ) {
      return 2.0 * PI * radius;
    }

  private:
    double radius;
};

When defining the member functions, they will be outside of the "class" block, yet we still need to tell the compiler they belong to the class. This is done by prefixing the function name with the class name and the :: operator.


class Circle {
  public:
    void setRadius(double r);
    double getArea( );
    double getCircumference( );

  private:
    double radius;
};

void Circle::setRadius(double r) {
  radius = r;
}

double Circle::getArea( ) {
  return PI * radius * radius;
}

double Circle::getCircumference( ) {
  return 2.0 * PI * radius;
}

Header Files & Source Files

There are two types of C++ files:

Header files are meant to declare classes and functions so that any code that needs the declarations can have them. This example shows the Circle class split into three files.

Notice that both .cpp files include the circle.h header file into them.


Separate Compilation

In order to call a function, it only must be declared, not defined. However to actually run the program, all functions must be defined.

There are actually several stages of compilation:

So far, we've had clang++ do all of these steps for us automatically. When writing code with multiple files, however, we must be aware of what each step does.


Include Guards

When using header files, it's possible to have double inclusion where the same header file ends up included in a source file two times. This example demonstrates this problem.

If we compile this, we will get errors like the following:


In file included from functions.h:2:0,
                 from main.cpp:4:
circle.h:4:14: error: redefinition of 'const double PI'
circle.h:4:14: error: 'const double PI' previously defined here
circle.h:6:7: error: redefinition of 'class Circle'
circle.h:6:14: error: previous definition of 'class Circle'

The problem is that we are redefining the values in circle.h when it is included in main.cpp. This is because the file is included twice. Once directly, and once through functions.h.

To avoid this, we can use an include guard. The form of an include guard is three lines of code in a header file: two at the top and one at the bottom. The two top lines look like this:


#ifndef FILENAME_H
#define FILENAME_H

The symbol used does not matter, but it must match on both lines, and be unique in your code. To ensure this, programmers often base it on the name of the file such as CIRCLE_H.

At the end of the file goes the line:


#endif

This works by telling the pre-processor to that if the symbol is not defined, define it and include all the code. If the symbol is defined (which means this file already got included somehow), then jump to the #endif.

This version of the above program has the include guards in place.


Guidelines for Using Multiple Files

Copyright © 2018 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.