Split between header and cpp in C++

I´m still a noob in C++, but after doing a little bit of research it seems like the strict split between header and cpp file is not enforced anymore.
I just absolutely hate it, I think it feels like an active action to make my code less readable and maintainable.
Is there any real benefit besides compile times?

The debates about to know if unity build and header-only is good or not, are rarelly interesting. Most of the time peoples have never managed themself a library/software of several thousands of files. And when they have, it’s hard to compare both approaches, since the work to change from one to the other is so huge that nobody will do it except when… be in danger of death. :grin:

My 2 cents.

1 Like

I used to be on team Header only. I’m now more in favour of split source for a couple of reasons:

  • Readability

    It’s a lot easier to scan through a header file without any implementations to get an idea of what methods are available and how the class should be used. juce_ValueTree.h is a good example of this. The header alone is ~600 lines long but clearly shows how the API can be used. Try doing the same with juce_ValueTree.cpp and it’s near impossible to get a good high-level overview of the class.
  • Free functions

    You can’t really do free functions in header files - not unless you want them to be public and available outside of a particular class. Putting free functions in .cpp files is the way to go.
    This is a great talk about free functions: CppCon 2017: Klaus Iglberger “Free Your Functions!” - YouTube
  • Code Reviews

    When you’re working in part of a team, it’s a lot easier to see in a commit’s changes list whether a class’s interface has changed (.h) or whether just the implementation has changed (.cpp). If the header has changed then I know I need to check everywhere the newly changed interface has been implemented. If only the implementation of the class has changed, I know I only really need to check that particular implementation.

There are some exceptions, templated classes for example I usually do header-only.

At the end of the day, it largely comes down to preference; if you prefer header only then go with that.

9 Likes

Damn you made some good points :expressionless:
I think I might try to split it for larger files.
It´s just for stuff like a single component or something where the split seems overkill.

And thanks for the link provided, will check that out!

1 Like

Like I said, there’s exceptions.
If I can fit a whole class in a header that’s under 150ish lines, I’ll likely just leave it header-only.

2 Likes

Great comments @ImJimmi I would add though that for templated classes you can still separate declaration and implementation.

What I’ve done in the past is have a .h and a .hpp file. I have the declarations in the .h, the implementation in the .hpp, and then include the .hpp file from the .h file (after the declaration).

If you think about it the only difference between this and the .h/.cpp pair is where the include happens, for a .cpp it includes the .h before the definitions, for a .hpp the .h includes it after the declarations.

Also if you want to limit your template class to a select few types then you can stick to the normal .h/.cpp pair, add the definitions to the .cpp and add some explicit instantiations so the linker can find the instantiations for the template arguments you want to support.

1 Like

That sounds like a great guideline. Thanks for the help!

I also used to be team Header Only for some time because it’s just so straightforward. And still I will stick to this pattern for small classes as already mentioned as well as for small header only libraries that should be easy to integrate for everyone.

But working in a company that evolved their product line from relatively simple to highly complex plugins, while sharing the same core codebase grown over years made me think more and more different. Seeing how a few minutes more or less compile time per build can make a difference in team productivity makes you think twice if you really want to implement something header only, where changing one line in this certain header that’s included in hundred other files over some corners will trigger a recompilation of all of those files, while with a split approach just the single cpp file would have been recompiled.

Of course this might or might not be a real concern for the type of project you are working on, but a lot of projects and codebases evolved and started from a quick proof of concept implementation that then survives for a longer time than ever expected :wink: And at some point, refactoring will become a real big task.

Another point not mentioned yet is cyclic dependency. There are situations where splitting interface and implementation is the only way to break up such issues.

5 Likes

I’m not sure about this since I didn’t test my self, but with C++20 module feature you could have something similar to a header only project, and avoid the include madness. I’m willing all the major compilers I need have it to start to use it (comeon Clang!!)

2 Likes

That was a very insightful answer, thank you.

3 Likes

Uhh didn´t see that one already existed.

Maybe one weird beginners question to wrap this thing here up.
When I write comments for my functions etc. in the header file it doesn´t apply to the .cpp.
Is there a specific tool needed in c++/visual studio so that I can hover over the methods in my cpp file and see its doc?
Or will I have to write it in both files?