Because when you're compiling another file, C++ doesn't actually need to know about the implementation. It only needs to know the signature of each function (which paramters it takes and what it returns), the name of each class, what macros are #define
d, and other "summary" information like that, so that it can check that you're using functions and classes correctly. The contents of different .cpp
files don't get put together until the linker runs.
For example, say you have foo.h
int foo(int a, float b);
and foo.cpp
#include "foo.h"
int foo(int a, float b) { /* implementation */ }
and bar.cpp
#include "foo.h"
int bar(void) {
int c = foo(1, 2.1);
}
When you compile foo.cpp
, it becomes foo.o
, and when you compile bar.cpp
, it becomes bar.o
. Now, in the process of compiling, the compiler needs to check that the definition of function foo()
in foo.cpp
agrees with the usage of function foo()
in bar.cpp
(i.e. takes an int
and a float
and returns an int
). The way it does that is by making you include the same header file in both .cpp
files, and if both the definition and the usage agree with the declaration in the header, then they must agree with each other.
But the compiler doesn't actually include the implementation of foo()
in bar.o
. It just includes an assembly language instruction to call foo
. So when it creates bar.o
, it doesn't need to know anything about the contents of foo.cpp
. However, when you get to the linking stage (which happens after compilation), the linker actually does need to know about the implementation of foo()
, because it's going to include that implementation in the final program and replace the call foo
instruction with a call 0x109d9829
(or whatever it decides the memory address of function foo()
should be).
Note that the linker does not check that the implementation of foo()
(in foo.o
) agrees with the use of foo()
(in bar.o
) - for example, it doesn't check that foo()
is getting called with an int
and a float
parameter! It's kind of hard to do that sort of check in assembly language (at least, harder than it is to check the C++ source code), so the linker relies on knowing that the compiler has already checked that. And that's why you need the header file, to provide that information to the compiler.