When writing projects in C++, file segmentation management is very necessary. Today, the editor of Foxin Technology Channel will bring you a detailed explanation of the header files and source files in C++. I hope it will be helpful for you to learn this knowledge!
Detailed explanation of header files and source files in C++
1. C++ compilation mode
Generally, in a C++ program, there are only two types of files - .cpp file and .h file. Among them, the .cpp file is called the C++ source file, and the source code of C++ is placed in it; while the .h file is called the C++ header file, and the source code of C++ is placed in it.
The C++ language supports "separate compilation". In other words, all the contents of a program can be divided into different parts and placed in different .cpp files. The things in the .cpp file are relatively independent. When compiling (compile), you do not need to communicate with other files. You only need to link with other target files after compiling it into the target file. For example, a global function "void a() {}" is defined in the file a.cpp, and this function needs to be called in the file b.cpp. Even so, the files a.cpp and b.cpp do not need to know each other's existence, but can compile them separately. After compiling them into the target file, link them, and the entire program can be run.
How is this achieved? From the perspective of writing programs, it is very simple. In the file b.cpp, before calling the "void a()" function, declare the function "void a();" first. This is because the compiler will generate a symbol table when compiling b.cpp. Symbols like "void a()" that cannot be seen will be stored in this table. When linking again, the compiler will look for the definition of this symbol in other object files. Once found, the program can be generated smoothly.
Note that there are two concepts mentioned here, one is "definition" and the other is "declaration". Simply put, "definition" means describing a symbol in a complete and complete way: whether it is a variable or a function, what type it returns, what parameters it needs, etc. "Declaration" just declares the existence of this symbol, that is, tells the compiler that this symbol is defined in other files. I will use it first. When you link, go to another place to find out what it is. When defining, you must define a symbol (variable or function) completely according to C++ syntax, and when declaring, you only need to write the prototype of this symbol. It should be noted that a symbol can be declared multiple times throughout the program, but must be defined only once. Just imagine, if there are two different definitions of a symbol, who should the compiler listen to?
This mechanism brings many benefits to C++ programmers, and also leads to a method of writing programs. Consider that if there is a very commonly used function "void f() {}" that will be called in many .cpp files in the entire program, then we only need to define this function in one file and declare this function in other files. A function is easy to deal with, and it only means one sentence to declare it. However, what if there are too many functions, such as a bunch of mathematical functions, there are hundreds of them? Can every programmer be sure to accurately write down and write down all functions in the form of them?
2. What is a header file
Obviously, the answer is impossible. But there is a very simple way to help programmers save the trouble of remembering so many function prototypes: we can write all the declaration statements of hundreds of functions first and put them in a file. When the programmer needs them, copy all these things into his source code.
This method is certainly feasible, but it is still too troublesome and seems clumsy. So, the header file can play its role. The so-called header file actually has the same content as the content in the .cpp file, both of which are C++ source code. But the header file does not need to be compiled. We put all function declarations into a header file. When a .cpp source file needs them, they can be included in this .cpp file through a macro command "#include", so that their contents are merged into the .cpp file. When the .cpp file is compiled, the functions of these included .h files are played.
Let’s give an example. Assume that all mathematical functions have only two: f1 and f2, then we put 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 put the declaration of the "those" functions in a header file math.h:
/* math.h */double f1();double f2(double);/* end of math.h */
In another file main.cpp, I want to call these two functions, so 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 */This is a complete program. It should be noted that the .h file does not need to be written after the compiler's command, but it must be found in the place where the compiler can find it (for example, in the same directory as main.cpp). main.cpp and math.cpp can be compiled to generate main.o and math.o respectively, and then link these two object files, and the program can be run.
3. #include
#include is a macro command from C language that works before the compiler compiles, that is, when precompiled. The purpose of #include is to completely and completely include the content of the file written after it into the current file. It is worth mentioning that it has no other functions or sub-functions. Its function is to replace every place it appears with the content of the file it writes behind it. Simple text replacement, nothing else. Therefore, the first sentence in the main.cpp file (#include "math.h") will be replaced with the contents of the math.h file before compilation. That is, when the compilation process is about to begin, the content of main.cpp has changed:
/* ~main.cpp */double f1();double f2(double);main(){ int number1 = f1(); int number2 = f2(number1);}/* end of ~main.cpp */No more or less, just right. Similarly, if we use f1 and f2 functions in addition to main.cpp, we only need to write a sentence #include "math.h" before using these two functions.
4. What should be written in the header file
Through the above discussion, we can understand that the function of the header file is to be included in other .cpps. They themselves do not participate in the compilation, but in fact, their contents are compiled in multiple .cpp files. Through the rule of "definition can only be once", we can easily conclude that only variables and functions declarations should be placed in the header file, and their definitions should not be placed. Because the contents of a header file will actually be introduced into multiple different .cpp files, and they will all be compiled. It is of course okay to put a declaration. If you put a definition, it is equivalent to a definition of a symbol (variable or function) appearing in multiple files. Even though these definitions are the same, it is not legal for the compiler to do so.
Therefore, one thing you should remember is that in the .h header file, there can only be variables or functions declarations, and do not place definitions. That is, sentences such as: extern int a; and void f(); can only be written in the header file. These are the statements. If you write a sentence like int a; or void f() {}, then once the header file is included in two or more .cpp files, the compiler will immediately report an error. (About extern, it has been discussed earlier, and the difference between definition and declaration will not be discussed here.) However, there are three exceptions to this rule.
1. The definition of the const object can be written in the header file. Because the global const object is not declared by extern by default, it is only valid in the current file. Write such an object into a header file, even if it is included in multiple other .cpp files, the object is only valid in the file containing it and is invisible to other files, so it will not lead to multiple definitions. At the same time, because the objects in these .cpp files are included from a header file, this ensures that the values of the const objects in these .cpp files are the same, which can be said to kill two birds with one stone. Similarly, the definition of the static object can also be put into the header file.
2. The definition of inline functions can be written in the header file. Because the inline function requires the compiler to inline according to its definition where it encounters it, rather than just an ordinary function that can be declared first and then linked (inline functions will not be linked), the compiler needs to see the complete definition of the inline function during compilation. If an inline function can only be defined once like a normal function, this will be difficult to do. Because it's okay in a file, I can write the definition of the inline function at the beginning, so that I can see the definition when I use it later; but what if I use this function in other files? There is almost no good solution to this, so C++ stipulates that inline functions can be defined multiple times in the program. As long as the inline function appears only once in a .cpp file, and in all .cpp files, the definition of this inline function is the same, and it can be compiled. Then obviously, it is very wise to put the definition of inline functions into a header file.
3. The definition of class can be written in the header file. Because when creating a class object in a program, the compiler can only know how the object of this class should be laid out when the definition of this class is completely visible, so the requirements for the definition of a class are basically the same as inline functions. Therefore, it is a good practice to put the class definition into the header file and include the header file in the .cpp file used in this class. Here, it is worth mentioning that the definition of a class contains data members and function members. Data members will not be defined until the specific object is created (allocated space), but function members need to be defined from the beginning, which is what we usually call the implementation of the class. Generally, our approach is to place the class definition in the header file, and put the implementation code of the function member in a .cpp file. This is OK and a good way. However, there is another way. That is to directly write the implementation code of function members into the class definition. In C++ classes, if function members are defined in the class definition body, the compiler will regard the function as inline. Therefore, it is legal to write the definition of function members into the class definition body and put them together into the header file. Note that it is illegal to write the definition of the function member in the header file of the class definition and not into the class definition, because the function member is not inline at this time. Once the header file is included in two or more .cpp files, this function member is redefined.
5. Protection measures in header files
Consider that if the header file only contains declaration statements, it will be fine if it is included in the same .cpp file many times - because the occurrence of declaration statements is unrestricted. However, the three exceptions in the header files discussed above are also a very common use of header files. Then, once any of the three exceptions above appear in a header file and it is included multiple times by a .cpp, the problem will be big. Because although the syntax elements in these three exceptions "can be defined in multiple source files", "can only appear once in one source file". Imagine that if ah contains the definition of class A and bh contains the definition of class B. Since the definition of class B depends on class A, ah is also #included in bh. Now there is a source file that uses both class A and class B, so the programmer includes both ah and bh in this source file. At this time, the problem arises: the definition of class A appears twice in this source file! So the entire program cannot be compiled. You might think it was a programmer's mistake - he should know that bh contains ah - but in fact he shouldn't.
Using "#define" with conditional compilation can solve this problem well. In a header file, a name is defined through #define, and #ifndef...#endif is conditionally compiled so that the compiler can decide whether to continue to compile the subsequent content in the header based on whether the name is defined. Although this method is simple, you must remember to write it in when writing the header file.
Thank you for reading this article. I hope the detailed explanation of the header files and source files in C++ introduced in this article can help you. Thank you for your support from the new technology channel network!