From what I have read and understood, the #include
directive in a source file, like for ex: main.cpp
, just copies the content of the included file to the .cpp
. So, when I include a header file, for ex: yum.h
, all the statements in yum.h
are copied into main.cpp
.
The header file will just have declarations and the actual definition will be in a corresponding .cpp
file, like yum.cpp
.
So, while compiling main.cpp
, how will the compiler know to look for the definition of any function mentioned in yum.h
in yum.cpp
? How will the compiler know to complie the yum.cpp
file too, as there is no reference to it in either main.cpp
file or yum.h
.
Also, why should yum.h
be included in yum.cpp
?
This may sound like a stupid question. I am a beginner to OOP and C++, and am just trying to understand what is happening.
Short answer: there is no relationship between the header and its implementation. One can exist without the other, or the two could be placed in files with unrelated names.
while compiling the
main.cpp
how will the compiler know to look for the definition of any function mentioned inyum.h
inyum.cpp
?
The compiler has no idea. Each time it sees a reference to something declared in yum.h
, or in any other header file, for that matter, it stays on a lookout for the corresponding definition.
If the definition is not there by the time the compiler has reached for the end of translation unit, it writes unsatisfied references into its main.o
output, noting the places from which they are coming from. This is called a symbol table.
Then the compiler compiles yum.cpp
, finds definitions from yum.h
in it, and writes their positions into yum.o
's symbol table.
Once all cpp
files have been processed, linker grabs all .o
files, and builds a combined symbol table from them. If unsatisfied references remain, it issues an error. Otherwise, it links references from main.o
with the corresponding symbols from yum.o
, completing the process.
Consider an example: let's say yum.h
declares a global variable int yum = 0
defined in yum.cpp
, and main.cpp
prints that variable. The compiler produces main.o
with a symbol table saying "I need int yum
's definition at address 1234", and yum.o
file's symbol table saying "I have int yum
at address 9876". Linker matches the "I need" with "I have" by placing 9876 at the address 1234.
The compiler does not need to look for anything in other code files.
The result of compilation is an object file, which has placeholders for whatever is defined in other code files. For making those placeholders, the compiler only needs the information provided by a suitable header (declarations, prototypes etc.).
The step of filling in the placeholders is the job of the linker, which is theoretically separate tool from the compiler. ("theoretically" as in "could be a single tool behaving like two separate tools.)
The reason for including the header with the declarations into the code file which does the implementing (of all or part of what gets declared) is a widely spread best practice, because it allows the compiler to complain if implementation and declaration do not match.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With