3

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.

  • "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?" thats the linkers job. – Borgleader Mar 17 '21 at 15:16
  • 1
    " I've looked through the compile process and linking process too" Take a closer look at linking. – Ben Voigt Mar 17 '21 at 15:16
  • "would it print "Hello" or "Bye"?" im pretty sure you would get a linker erreor from having 2 definitions of the same function – Borgleader Mar 17 '21 at 15:17
  • BTW the linker is doing the same job with your functions that it does with library functions. Compiling your program would be really slow if there were no separate linker, because the system header files would have to contain the complete definitions of all library functions and the compiler would have to re-optimize the whole library for each change you make to your code. Avoiding that is the point of having multiple compilation units linked together. – Ben Voigt Mar 17 '21 at 15:18
  • Also, it is possible to include other source units, doing so is called a "Unity Build". discussion here: https://stackoverflow.com/q/847974/103167 – Ben Voigt Mar 17 '21 at 15:20

2 Answers2

7

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.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
0

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.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165