Understanding the Role of Header Files and Source Files in C++
Category Programming Techniques
I. C++ Compilation Model
Typically, a C++ program consists of two types of files—.cpp files and .h files. The .cpp files are known as C++ source files, which contain the actual C++ source code; whereas the .h files are referred to as C++ header files, which also contain C++ source code.
The C++ language supports "separate compilation." This means that all the content of a program can be divided into different parts and placed into different .cpp files. The contents of a .cpp file are relatively independent and do not require communication with other files during compilation. They only need to be linked with other object files after compilation to form a runnable program. For example, if a global function "void a() {}" is defined in file a.cpp, and another file b.cpp needs to call this function, a.cpp and b.cpp do not need to be aware of each other's existence. They can be compiled separately, and once compiled into object files, they can be linked together to run the program.
How is this achieved? From a programming perspective, it's quite simple. In file b.cpp, before calling the "void a()" function, declare the function first with "void a();". This is because the compiler generates a symbol table when compiling b.cpp, and symbols like "void a()" without definitions are stored in this table. During the linking process, the compiler searches for the definition of this symbol in other object files. Once found, the program can be successfully generated.
II. What is a Header File
Obviously, the answer is not possible. However, there is a simple method that can help programmers avoid the hassle of remembering so many function prototypes: we can write all the declaration statements of those hundreds of functions in advance and place them in a file. When a programmer needs them, he can copy all these things into his source code.
This method is certainly feasible but too cumbersome and clumsy. Thus, the header file can play its role. The so-called header file has the same content as the .cpp file, which is C++ source code. However, the header file does not need to be compiled. We put all the function declarations into a header file, and when a .cpp source file needs them, they can be included into this .cpp file through a macro command "#include", thus merging their content into the .cpp file. When the .cpp file is compiled, the role of the included .h file is played.
Let's take an example. Suppose there are only two mathematical functions: f1 and f2, and we place their definitions in math.cpp:
/* math.cpp */
double f1()
{
//do something here....
return;
}
double f2(double a)
{
//do something here...
return a * a;
}
/* end of math.cpp */
And place the declarations of "these" functions in a header file math.h:
/* math.h */
double f1();
double f2(double);
/* end of math.h */
In another file main.cpp, if I want to call these two functions, I just need to include the header file:
/* main.cpp */
#include "math.h"
main()
{
int number1 = f1();
int number2 = f2(number1);
}
/* end of main.cpp */
In this way, a complete program is formed. It should be noted that the .h file does not need to be written after the compiler's command, but it must be in a place where the compiler can find it (for example, in the same directory as main.cpp). Both main.cpp and math.cpp can be compiled separately to generate main.o and math.o, and then link these two object files, and the program can run.
III. #include
include is a macro command from the C language, which takes effect before the compiler compiles, that is, during the pre-compilation. The role of #include is to include the content of the file written after it, completely and unchanged, into the current file. It is worth mentioning that it has no other functions or side effects. Its function is to replace every place where it appears with the content of the file written after it. Simple text replacement, nothing more. Therefore, the first sentence in the main.cpp file (#include"math.h") will be replaced with the content of the math.h file before compilation. That is, before the compilation process is about to start, the content of main.cpp has changed:
/* ~main.cpp */
double f1();
double f2(double);
main()
{
int number1 = f1();
int number
In Tan Haoqiang's book "C Program Design," it is mentioned that during the pre-processing of the compiler, the "file inclusion processing" is performed for the #include command: the entire content of file2.c is copied to the location of #include "file2.c". This also explains why many compilers do not care about the file extension because the #include preprocessing is essentially a "copy and insert code" job.
During compilation, the implementation of functions in the b.cpp file is not sought; this task is performed during the linking phase. When we use #include "a.h" in b.cpp or c.cpp, we are actually introducing relevant declarations to ensure the compilation passes. The program does not care where or how the implementation is done. After the source file is compiled, it generates an object file (.o or .obj file), and in the object file, these functions and variables are treated as symbols. During the linking phase, it is necessary to specify in the makefile which .o or .obj file needs to be linked (in this case, the .o or .obj file generated by b.cpp). At this time, the linker will look for the functions implemented in b.cpp in the .o or .obj file and then build them into the executable file specified in the makefile.
Under Unix, it is even possible not to include the header file in the source file, just specify it in the makefile (but this greatly reduces the readability of the program, which is a bad habit ^_^). In VC, you generally do not need to write your own makefile; just include all the necessary files in the project, and VC will automatically write the makefile for you.
Usually, the C++ compiler will look for the required symbols in each .o or .obj file, rather than just looking in one file or stopping after finding one. Therefore, if the same function is implemented in several different files, or the same global variable is defined, the linker will prompt "redefined" during the linking process.
### In summary,
.h files can include:
- Declarations of class member data, but no assignments can be made.
- Definitions and assignments of class static data members, but it is not recommended; just a declaration is fine.
- Declarations of class member functions.
- Declarations of non-class member functions.
- Definitions of constants: for example, const int a = 5;
- Definitions of static functions.
- Definitions of class inline functions.
Cannot include:
- 1. Declarations of all non-static variables (not class data members).
- 2. Default namespace declarations should not be placed in header files; using namespace std; etc., should be placed in .cpp files, and std::string should be used in .h files.
>
Original article link: https://blog.csdn.net/qq_35038153/article/details/71293265
#
-
** HexToString
** 506***[email protected]
There is an error, little buddy.
The rest is written quite well, but there is a small error that needs to be pointed out. `.h` files can include: definitions of `static` ordinary variables and functions, but they cannot include definitions of `static` member functions and member variables.
The reason is that the keyword **static** actually has two different meanings:
- When **static** modifies ordinary variables and functions.
- The keyword **static** is to limit visibility.
For example:
`void funcA(){ int a =0; a++; printf(a) }`, if you want to continuously record how many times it has been called, you need to use a global variable, but global variables are too exposed, and they can be seen in other files, so static a is used to make it visible only in this file.
When static modifies class member variables, the member belongs to the class itself, and all instances of the class share it.
class A{ public: static int a; } ```
When other files include the class definition header file classA.h, it is essentially equivalent to copying. Suppose we do not #include "classA.h"
now but write it directly.
For example, a.cpp writes the above header file, and then adds int A::a = 3;
, and then in b.cpp, write the above header file, and then add int A::a = 3;
, which is equivalent to defining it twice, and at this time, a redefinition problem occurs (the root lies in the fact that static member variables do not limit visibility to only this file), so the header file cannot include the definition of static member functions and member variables, only declarations can be made.
** HexToString
* 506**[email protected]
** Click to share my notes
-
-
-