1. Introduction
In common C/C ++ development, almost all people are used to separating classes and functions. put the declaration in the header file of h, corresponding. c or. put the implementation in cpp. From initial contact to skillful use, almost a subconscious process has been formed. Although such an approach is understandable, and in many cases it is relatively reasonable or even necessary, I would like to introduce you to the way in which all implementations are placed in the header file, provide another option for your use. At the same time, the advantages and disadvantages of this practice and the situations that need attention are also mentioned by the way.
I am a simple person and have even developed this kind of hobby for many years. If a function can be implemented with one statement, do not use two statements. In my opinion, if you provide a reusable code to others, the most elegant state is to simply provide a header file. The most important reason why I do not like to introduce source files is that the source files often lead to changes in engineering files. In addition, some additional operations will be added during use, for example, in a well-organized project, the header file and source file may be located in different directories, which leads to an additional file copy operation.
2. Text
2.1 concerns
I have met many people who do not use header files to include implementations. This is often due to the following concerns:
1. Exposed Implementation Details
2. If the header file is included in different source files, link conflicts may occur.
3. If the header file is included in different source files, multiple implementations will be compiled to increase the size of the executable body.
If there is concern 1, it is obvious that you should discard the idea of completely implementing it in the header file in the first time. However, in my case, the latter two concerns usually account for an absolute proportion. This concern is usually caused by insufficient understanding of C/C ++.
If you have concerns 2, you will often be a programmer with C language development experience. They are also worried about global functions. For example, the following header file c_function.h (for clarity, Code such as defense macros is not listed ):
[Cpp]
Int integer_add (const int a, const int B)
{
Return a + B;
}
If. c (or. cpp) and B. if two (or more) c source files contain this header file, a conflict occurs during the link period, because the two source files are compiled with the function implementation of integer_add, as a result, the linker does not know which copy should be used for callers who call this function.
Starting from 2.2
There are two solutions, each with two keywords: inline and static. Using any of the two keywords to modify the integer_add function will eliminate the aforementioned conflicts, but the essence is quite different.
If inline is used, it means that the compiler inserts the target code of the function directly at the place where the function is called, instead of placing a real function call. The actual function is that the function actually does not exist, it is expanded in place like a macro. The side effects of using inline are undoubtedly that the size of the Code increases. Secondly, this keyword is not a keyword of C language, using it may bring some portability risks, even though mainstream C-language compilers support inline. For GCC, the keyword of the inline function is inline itself, and for Microsoft compiler, it should be _ inline (note that there are two leading underlines ). In addition, according to the Convention, inline is usually a hint of the compiler rather than a forcible requirement. the compiler has the power to implement it into a non-inline state without your knowledge (possibly because, function is too large or too complex ). What are the consequences? Sorry, I have never tested it.
If static is used, at least the result is predictable. A copy of this function exists in all the source files that contain this header file. Although the Code expands to a certain extent, it is better that the Code does not conflict with each other, because the static keyword ensures that the visibility of the function is within a single source file.
Although the above discussion seems to focus mainly on the C language, since C ++ is a superset of the C language and has not made too many changes in these aspects, therefore, the discussion results also apply to C ++.
2.3 continue
For the C language, the above improvements have almost come to an end and there is no room for further development. However, for C ++, we can make it more beautiful.
First, make the following changes:
[Cpp]
Class Integer
{
Public:
Int add (int a, int B)
{
Return a + B;
}
};
Almost all beginners of C ++ can see this form, and there will be no connection conflicts any more. However, there is also a problem. If we want to calculate the sum of two integers, We need to write as follows:
Integer op;
Op. add (I, j );
This is obviously not an acceptable state. The call of a simple function statement must now define an object instance of a class. So we turn to static again (inline is not applicable because it cannot remove the definition object instance step, and in fact, the default function that writes the implementation to the class definition is inline ). Now, the class looks like this:
[Cpp]
Class Integer
{
Public:
Static int add (int a, int B)
{
Return a + B;
}
};
The call method is also simplified as follows:
Integer: add (I, j );
In particular, the static functions in the C ++ class are different from the Global static functions. After compilation, only one implementation code is generated, multiple copies are not generated because they are included in multiple source files.
This is not far from our ultimate goal (our ultimate goal is: add (I, j ). So we once again held up the macro, and added the following definition in the header file:
# Define integer_add Integer: add (after Note: suddenly, it seems that defining the const function pointer can achieve the same purpose)
The above only solves the problem of header file reuse of global functions in C ++. What about classes? Class is more complex. If it is a static method, it is exactly the same as the above implementation of the global function; if it is an inline method (whether there is any inline keyword ), the State is almost theoretically equivalent to the inline global function described above. The last case is the virtual function. For a virtual function, we wait for the good news: it always generates a piece of code (or even explicitly using the inline keyword ). There is a xuanjicang: the address of the virtual function will be written to the v-table of the class, which must be called during the runtime (the core is that, the caller and the call time are unclear during compilation). Therefore, it cannot be produced in the form of full local expansion. In this way, we can make an inference: all the member functions that will be evaluated will generate a function entity, rather than simply conforming to the inline modifier keywords.
3. Postscript
Of course, putting all implementations in the header file is not a panacea, not a universal rule. As mentioned at the beginning of this article, this is just a choice, but you have never thought of doing so before, now we know. It is most suitable for implementation of some small tool classes.