1. the header file is used for declaration instead of definition.
Remember the differences between definitions and declarations when designing header files. The definition can appear only once, while the Declaration can appear multiple times (Section 2.3.5 ). The following statements are some definitions, so they should not be placed in the header file:
Extern int ival = 10; // initializer, so it's a definition
Double fica_rate; // No extern, so it's a definition
Although ival is declared as extern, it has an initialization type, which indicates that this statement is a definition. Similarly, although the fica_rate statement has no initialization type, it is also a definition because there is no keyword extern. If two or more files in the same program contain any of the preceding definitions, multiple definitions may be linked incorrectly.
Because the header file is contained in multiple source files, it should not contain the definition of variables or functions.
The header file should not contain this rule, with three exceptions. The header file can define classes and const objects and inline functions that are known at compilation (section 7.6 describes the inline function ). These entities can be defined in multiple source files, as long as the definitions in each source file are the same.
Define these entities in the header file because the compiler needs their definitions (not just declarations) to generate code. For example, to generate code that can define or use class objects, the compiler needs to know the data members that constitute this type. You also need to know the operations that can be performed on these objects. Class definition provides the required information. Defining the const object in the header file requires more explanation.
2. SomeConstObject definition in header file
Recall that the const variable (Section 2.4) is the local variable of the file defining the variable by default. As we can see now, the default reason for this is to allow the const variable to be defined in the header file.
In C ++, constant expressions must be placed in some places (section 2.7 ). For example, the initialization type of the enumerated member must be a constant expression. In the following sections, we will see examples of other constant expressions.
In general, constant expressions are the expressions that the compiler can calculate at compilation. When a const integer variable is initialized through a constant expression, this const integer variable may be a constant expression. To make the const variable a constant expression, the initialization must be visible to the compiler. To allow multiple files to use the same constant value, the const variable and its initialization must be visible to each file. To make the initialization visible, such const variables are generally defined in the header file. In this case, the compiler will be able to see its initialization method no matter when the const variable is used.
However, any variable in C ++ can be defined only once (Section 2.3.5 ). Definition will allocate a bucket, and all usage of this variable will be associated with the same bucket. Because the const object is the local variable that defines its file by default, it is legal to put their definitions in the header file.
This behavior has a very important meaning: After we define the const variable in the header file, each source file containing the header file has its own const variable, and its name and value are the same.
When the const variable is initialized using a constant expression, it can ensure that all variables have the same value. However, in practice, most compilers replace any usage of these const variables with corresponding constant expressions during compilation. Therefore, in practice, no storage space is used to store the const variable initialized with a constant expression.
If the const variable is not initialized using a constant expression, it should not be defined in the header file. On the contrary, like other variables, the const variable should be defined and initialized in a source file. The extern declaration should be added to the header file so that it can be shared by multiple files.
Exercise
Exercise 2.31 identifies which of the following statements are declarations and definitions, and explains the reasons.
(A) extern int IX = 1024;
(B) int Iy;
(C) extern int iz;
(D) extern const Int & Ri;
Exercise 2.32 which of the following statements and definitions should be included in the header file? Which should be placed in the source file? And explain the cause.
(A) int var;
(B) const double Pi = 3.1416;
(C) extern int Total = 255;
(D) const double sq2 = squt (2.0)
Exercise 2.33: Determine which warning-level options your compiler provides. Use these options to re-compile the previously selected program and check whether new problems are reported.
2.9.2 introduction to preprocessors
Now that we know what to put in the header file, the next question is to write the header file. We know that to use a header file, you must # include this header file in the source file. To write header files, we need to further understand how the # include directive works. # The include facility is part of the C ++ Preprocessor. Source code of the pre-processor, which runs before the compiler. C ++ inherits a very fine pre-processor of C. The current C ++ program uses the pre-processor in a highly restricted manner.
# Include indicates that only one parameter is accepted: the header file name. The Preprocessor replaces each # include with the content of the specified header file. Our own header files are stored in files. System header files may be saved in a more efficient format specific to the compiler. Regardless of the format in which the header file is saved, it generally contains the class definitions and declarations of variables and functions required for separation and compilation.
1. Other header files are often required for header files.
Header files often # include other header files. Objects defined in header files often use other header file facilities. For example, the header file defining the sales_item class must contain the string library. The sales_item class contains a string-type data member. Therefore, you must be able to access the string header file.
It is so common to include other header files. It is not uncommon to include a header file multiple times into the same source file. For example, programs that use the sales_item header file may also use the string library. This program does not (and should not) know that the sales_item header file uses the string library. In this case, the string header file is included twice: one is directly included by the program itself, and the other is indirectly included by containing the sales_item header file.
Therefore, it is important to design a header file so that it can be included in the same source file multiple times. We must ensure that multiple times containing the same header file will not cause the class and object defined by this header file to be defined multiple times. A common practice for header file security is to use a Preprocessor to define header file guard ). The header file sentry is used to avoid re-processing the content of the header file when the header file has been seen.
2. Avoid Multiple inclusion
Before writing header files, we need to introduce some additional pre-processor facilities. The Preprocessor allows us to customize variables.
The Preprocessor variable name must be unique in the program. Any use of names that match the Preprocessor variable is associated with the Preprocessor variable.
To avoid name conflicts, Preprocessor variables are often expressed in uppercase letters.
Preprocessor variables have two states: defined or undefined. Different pre-processor indicators are used to define pre-processor variables and to detect their statuses. # Define indicates accepting a name and defining it as a Preprocessor variable. # Ifndef indicates whether to check whether the specified Preprocessor variable is undefined. If the Preprocessor variable is undefined, all the subsequent commands are processed Until # endif appears.
You can use these facilities to prevent multiple times containing the same header file:
# Ifndef salesitem_h
# Define salesitem_h
// DefinitionSales_itemClass and related functions goes here
# Endif
Conditional instruction
# Ifndef salesitem_h
Test whether the Preprocessor variable salesitem_h is undefined. If salesitem_h is not defined, # ifndef test is successful. All the rows following # ifndef are executed until # endif is found. Conversely, if salesitem_h is defined, # ifndef indicates that the test is false, and the code between the instruction and # endif indicates is ignored.
To ensure that the header file is only processed once in the given source file, we first detect # ifndef. When the header file is processed for the first time, the test succeeds because salesitem_h is not defined yet. The next statement defines salesitem_h. In that case, if the compiled file exactly contains the header file again. # Ifndef indicates that salesitem_h has been defined and the rest of the header file is ignored.
The header file should contain the sentry, even if these header files are not included by other header files. It is not difficult to compile the header file Sentinel. If the header file is contained multiple times, it can avoid compilation errors that are hard to understand.
This policy is effective when no header file is defined and a Preprocessor constant with the same name is used. We can name Preprocessor variables for entities (such as classes) defined in header files to avoid the problem of duplicate Preprocessor variables. A program can contain only one class named sales_item. By using a class name to form the names of header files and Preprocessor variables, it is possible that only one file will use the Preprocessor variable.
3. Use custom header files
# The include Directive accepts the following two forms:
# Include <standard_header>
# Include "my_file.h"
If the header file name is enclosed in angle brackets (<>), the header file is considered as a standard header file. The compiler will find this header file in the predefined location set. These predefined locations can be modified by setting the PATH environment variable or using the command line option. The search methods used vary with compilers. It is recommended that you consult a colleague or consult the compiler user guide for more information. If the header file name is enclosed in a pair of quotation marks, it is considered to be a non-system header file. The search for a non-system header file usually begins with the path of the source file.