Why do we include header files and not source files?

Viewed 322

I've seen similar questions asked yet they still do not make sense to my ape brain.

Here is an example. If I declared a function in a header file named Bob.h: void PrintSomething(); and in the .cpp file I say: void MyClass::PrintSomething(){std::cout << "Hello";} . I've seen people in another .cpp file for example Frank.cpp, only include the Bob.h header which just has the declaration (No code inside it) and not the .cpp with the code but then what blows my mind is when they call the PrintSomething() function in Frank.cpp it uses the code from Bob.cpp and prints "Hello". How? How does it print "Hello" which was added in the .cpp file when I've only included the .h file which doesn't say anything about "Hello", its just a declaration? I've looked through the compile process and linking process too but it just doesn't stick.

On top of which if I were to now say in my Frank.cpp file: void MyClass::PrintSomething(){std::cout << "Bye";} and included the Bob.h file in my main.cpp and called the PrintSomething() function would it print "Hello" or "Bye"? Is the computer psychic or something? This concept is the one thing I am not grasping in my C++ learning journey.

Thanks in advance.

2 Answers

The moment you include Bob.h the compiler has everything it needs to know about PrintSomething(), it only need a declaration of the function. Frank.cpp does not need to know about Bob.cpp which defines PrintSomething().

All of your individual cpp files output object files generated by the compiler. These in themselves don't do much until they're all glued together, this is the linker's responsibility.

The linker takes all your object files and fills in the missing parts:

Linker talk:

Hey, I see that Frank.obj uses PrintSomething() and I can't see its definition in that object file.

Let's check the other object files..

Upon inspecting Bob.obj I can see that this contains a usable definition for PrintSomething(), let's use that.

This is of course simplified but that's what a linker does in short.

After this is done you get your usable executable.


on top of which if I were to now say in my Frank.cpp file: void MyClass::PrintSomething(){std::cout << "Bye";} and included the Bob.h file in my main.cpp and called the PrintSomething() function would it print "Hello" or "Bye"? Is the computer psychic or something?

The linker would find 2 definitions of PrintSomething() and would emit an error, it has no way to know what definition is the right one to pick.

The key notion here is separate compilation. You divide your project into a set of source files that implement more-or-less independent things, you compile those source files into object files, and you link the object files and any additional libraries (including the standard library) to create an executable file. For large projects, compiling all of the source files can take a long time (sometimes measured in hours). The first time you build your application you have to do that. But after that, if you only changed one source file you only need to recompile that source file and then link again, which the object files that you created the first time through. That's usually a big time saver. If you have one massive source file (i.e., a source file that #includes all the rest of your source files), you don't get that option -- you have to recompile the whole thing every time.

Related