Search code examples
c++cheader-filescode-maintainability

Why are function bodies in C/C++ placed in separate source code files instead of headers?


For instance, when I define a class file in C++ I've always put the function bodies in the class header files (.h) along with the class definition. The source code file (.cpp) is the one with the main() function. Now is this commonly done among pro c++ programmers or do they follow the convention of separate header/source code files.

As for native C, I do notice then done in GCC (and of course for the headers in Visual Studio for Windows).

So is this just a convention? Or is there a reason for this?


Solution

  • Function bodies are placed into .cpp files to achieve the following:

    1. To make the compiler parse and compile them only once, as opposed to forcing it to compile them again, again and again everywhere the header file is included. Additionally, in case of header implementation linker will later have to detect and eliminate identical external-linkage functions arriving in different object files.

      Header pre-compilation facilities implemented by many modern compilers might significantly reduce the wasted effort required for repetitive recompilation of the same header file, but they don't entirely eliminate the issue.

    2. To hide the implementations of these functions from the future users of the module or library. Implementation hiding techniques help to enforce certain programming discipline, which reduces parasitic inter-dependencies between modules and thus leads to cleaner code and faster compilation times.

      I'd even say that even if users have access to full source code of the library (i.e. nothing is really "hidden" from them), clean separation between what is supposed to be visible through header files and what is not supposed to be visible is beneficial to library's self-documenting properties (although such separation is achievable in header-only libraries as well).

    3. To make some functions "invisible" to the outside world (i.e. internal linkage, not immediately relevant to your example with class methods).

    4. Non-inline functions residing in a specific translation unit can be subjected to certain context-dependent optimizations. For example, two different functions with identical tail portions can end up "sharing" the machine code implementing these identical tails.

      Functions declared as inline in header files are compiled multiple times in different translation units (i.e. in different contexts) and have to be eliminated by the linker later, which makes it more difficult (if at all possible) to take advantage of such optimization opportunities.

    5. Other reasons I might have missed.