- 3.1 Introduction
- 3.2 Separate Compilation
- 3.3 Modules (C++20)
- 3.4 Namespaces
- 3.5 Error Handling
- 3.6 Function Arguments and Return Values
- 3.7 Advice
3.2 Separate Compilation
C++ supports a notion of separate compilation where user code sees only declarations of the types and functions used. The definitions of those types and functions are in separate source files and are compiled separately. This can be used to organize a program into a set of semi-independent code fragments. Such separation can be used to minimize compilation times and to strictly enforce separation of logically distinct parts of a program (thus minimizing the chance of errors). A library is often a collection of separately compiled code fragments (e.g., functions).
Typically, we place the declarations that specify the interface to a module in a file with a name indicating its intended use. For example:
// Vector.h: class Vector { public: Vector(int s); double& operator[](int i); int size(); private: double* elem; // elem points to an array of sz doubles int sz; };
This declaration would be placed in a file Vector.h. Users then include that file, called a header file, to access that interface. For example:
// user.cpp: #include "Vector.h" // get Vector's interface #include <cmath> // get the standard-library math function interface including sqrt() double sqrt_sum(Vector& v) { double sum = 0; for (int i=0; i!=v.size(); ++i) sum+=std::sqrt(v[i]); // sum of square roots return sum; }
To help the compiler ensure consistency, the .cpp file providing the implementation of Vector will also include the .h file providing its interface:
// Vector.cpp: #include "Vector.h" // get Vector's interface Vector::Vector(int s) :elem{new double[s]}, sz{s} // initialize members { } double& Vector::operator[](int i) { return elem[i]; } int Vector::size() { return sz; }
The code in user.cpp and Vector.cpp shares the Vector interface information presented in Vector.h, but the two files are otherwise independent and can be separately compiled. Graphically, the program fragments can be represented like this:
Strictly speaking, using separate compilation isn’t a language issue; it is an issue of how best to take advantage of a particular language implementation. However, it is of great practical importance. The best approach to program organization is to think of the program as a set of modules with well-defined dependencies, represent that modularity logically through language features, and then exploit the modularity physically through files for effective separate compilation.
A .cpp file that is compiled by itself (including the h files it #includes) is called a translation unit. A program can consist of many thousand translation units.