Although as we’ll see in § 19.7 (p. 852), we can define a class inside a function, such classes have limited functionality. As a result, classes ordinarily are not defined inside functions. When we define a class outside of a function, there may be only one definition of that class in any given source file. In addition, if we use a class in several different files, the class’ definition must be the same in each file.
In order to ensure that the class definition is the same in each file, classes are usually defined in header files. Typically, classes are stored in headers whose name derives from the name of the class. For example, the string
library type is defined in the string
header. Similarly, as we’ve already seen, we will define our Sales_data
class in a header file named Sales_data.h
.
Headers (usually) contain entities (such as class definitions and const
and constexpr
variables (§ 2.4, p. 60)) that can be defined only once in any given file. However, headers often need to use facilities from other headers. For example, because our Sales_data
class has a string
member, Sales_data.h
must #include
the string
header. As we’ve seen, programs that use Sales_data
also need to include the string
header in order to use the bookNo
member. As a result, programs that use Sales_data
will include the string
header twice: once directly and once as a side effect of including Sales_data.h
. Because a header might be included more than once, we need to write our headers in a way that is safe even if the header is included multiple times.
Whenever a header is updated, the source files that use that header must be recompiled to get the new or changed declarations.
The most common technique for making it safe to include a header multiple times relies on the preprocessor. The preprocessor—which C++ inherits from C—is a program that runs before the compiler and changes the source text of our programs. Our programs already rely on one preprocessor facility, #include
. When the preprocessor sees a #include
, it replaces the #include
with the contents of the specified header.
C++ programs also use the preprocessor to define header guards. Header guards rely on preprocessor variables (§ 2.3.2, p. 53). Preprocessor variables have one of two possible states: defined or not defined. The #define
directive takes a name and defines that name as a preprocessor variable. There are two other directives that test whether a given preprocessor variable has or has not been defined: #ifdef
is true if the variable has been defined, and #ifndef
is true if the variable has not been defined. If the test is true, then everything following the #ifdef
or #ifndef
is processed up to the matching #endif
.
We can use these facilities to guard against multiple inclusion as follows:
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
struct Sales_data {
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
#endif
The first time Sales_data.h
is included, the #ifndef
test will succeed. The preprocessor will process the lines following #ifndef
up to the #endif
. As a result, the preprocessor variable SALES_DATA_H
will be defined and the contents of Sales_data.h
will be copied into our program. If we include Sales_data.h
later on in the same file, the #ifndef
directive will be false. The lines between it and the #endif
directive will be ignored.
Preprocessor variables, including names of header guards, must be unique throughout the program. Typically we ensure uniqueness by basing the guard’s name on the name of a class in the header. To avoid name clashes with other entities in our programs, preprocessor variables usually are written in all uppercase.
Headers should have guards, even if they aren’t (yet) included by another header. Header guards are trivial to write, and by habitually defining them you don’t need to decide whether they are needed.