The problem lies in the field of backward compatibility.
Look, any new programming language - yes, even Pascal, not to mention Java or C # - do not need header files. Without a doubt, C ++ could also do without them. What's the matter?
Fast forward half a century ago, in 1972. Imagine a C compiler.
Suppose we want to write a compiler design. We can not compile the entire program at once, we just do not have enough memory. Computers were then small and slow. We want to compile the program piece by piece, several functions at a time.
We immediately have a problem: how to compile the function f , which refers to another function g ? We need a separate description of other functions. We could, of course, read all the source files, first find out what features we have, and then read them a second time and compile one by one. But it was too difficult and slow, it was necessary to parse the function definitions twice, and throw the result once! This is unacceptable CPU time! Plus, if you keep in mind the definitions of all functions, it may again not be enough memory.
On whom Dennis decided to put the difficult problem of separating the description of the function from its implementation, and connecting only the necessary descriptions when compiling this function? On us, programmers. He decided that we should help the compiler and copy the definitions of the functions into a separate file, and tell the compiler what files with the definitions are needed. (That is, the first compilation step is on us.)
This radically simplified the compiler, but in turn led to problems. What happens if we forget to include the necessary header file? Answer: compilation error. What happens if the meaning of the text in the header file changes depending on a macro? Answer: the compiler is "stupid", and does not try to detect this problem, it shifts the responsibility to us.
At the time of the development of the language it was the right decision. The compiler turned out to be practical, fast, and programmers were not averse to helping the compilation. Well, if anyone made a mistake, he himself was to blame.
Rewind hands of clocks in 1983. Bjarn creates C ++. He decided to take off in the wake of the popularity of the C language, and adopted the C compilation model with separate translation units and related problems directly from C. However, the first versions of C ++ were just a preprocessor of the C language! Therefore, separate compilation problems migrated from C to C ++. Worse, new problems have been added. For example, class templates look like classes, but do not generate an object code by themselves, so they have to go for tricks and bypass the disadvantages of a separate compilation system (for example, including the implementation in the header and linker tricks).
And then backward compatibility came into play. Now, in 2017, there is so much code written in the “with headers” style, and so much code comes from various subtleties associated with this that it is too late to change the paradigm, the train has almost left.
However, there is a project for a modular system in C ++, which should help programmers get rid of a legacy of half a century ago. It has not yet been implemented, and there are difficulties in the design level (for example, a macro has been defined in the header, will it be visible if we move from the header to the modules?) I hope in the future developers of the language will be able to overcome the inverse problem compatibility.