222

My personal style with C++ has always to put class declarations in an include file, and definitions in a .cpp file, very much like stipulated in Loki's answer to C++ Header Files, Code Separation. Admittedly, part of the reason I like this style probably has to do with all the years I spent coding Modula-2 and Ada, both of which have a similar scheme with specification files and body files.

I have a coworker, much more knowledgeable in C++ than I, who is insisting that all C++ declarations should, where possible, include the definitions right there in the header file. He's not saying this is a valid alternate style, or even a slightly better style, but rather this is the new universally-accepted style that everyone is now using for C++.

I'm not as limber as I used to be, so I'm not really anxious to scrabble up onto this bandwagon of his until I see a few more people up there with him. So how common is this idiom really?

Just to give some structure to the answers: Is it now The Way™, very common, somewhat common, uncommon, or bug-out crazy?

T.E.D.
  • 41,324
  • 8
  • 64
  • 131
  • 2
    one-line functions (getters and setters) in the header is common. Longer than would get a quizzical second glance. Perhaps for the complete definition of a small class that is only used by another in the same header? – Martin Beckett Feb 25 '09 at 00:06
  • i have always put all my class definitions in headers so far. only definitions for pimpl classes are the exceptions. i only declare those in headers. – Johannes Schaub - litb Feb 25 '09 at 00:26
  • 3
    Maybe he thinks its the way because thats how Visual C++ insists that code be written. When you click on a button, the implementation is generated in the header file. I dont know why Microsoft would encourage this though for the reasons others have explained below. – W.K.S Jun 30 '12 at 05:27
  • 6
    @W.K.S - Microsoft would rather everyone program in C#, and in C#, there is no "header" vs "body" distinction, it is just one file. Having been in both C++ and C# worlds for a long time now, the C# way is actually much easier to deal with. – Mark Lakata Feb 19 '15 at 00:36
  • 1
    @MarkLakata - That is indeed one of the things he pointed to. I haven't heard this argument out of him lately, but IIRC he was arguing that Java and C# work this way, and C# was brand new at the time, which made it a trend all languages will soon be following – T.E.D. Feb 19 '15 at 14:22
  • You can use [explicit template instantiation](http://en.cppreference.com/w/cpp/language/class_template) and export explicit template instantiations and move some of your templated code to the cpp files as well. For example, you can have a cpp file that explicitly instantiates vector if you use it many times in different units, and then avoid paying for reinstantiation in other translation units. – Mani Zandifar Oct 22 '15 at 05:57

17 Answers17

234

Your coworker is wrong, the common way is and always has been to put code in .cpp files (or whatever extension you like) and declarations in headers.

There is occasionally some merit to putting code in the header, this can allow more clever inlining by the compiler. But at the same time, it can destroy your compile times since all code has to be processed every time it is included by the compiler.

Finally, it is often annoying to have circular object relationships (sometimes desired) when all the code is the headers.

Bottom line, you were right, he is wrong.

EDIT: I have been thinking about your question. There is one case where what he says is true. templates. Many newer "modern" libraries such as boost make heavy use of templates and often are "header only." However, this should only be done when dealing with templates as it is the only way to do it when dealing with them.

EDIT: Some people would like a little more clarification, here's some thoughts on the downsides to writing "header only" code:

If you search around, you will see quite a lot of people trying to find a way to reduce compile times when dealing with boost. For example: How to reduce compilation times with Boost Asio, which is seeing a 14s compile of a single 1K file with boost included. 14s may not seem to be "exploding", but it is certainly a lot longer than typical and can add up quite quickly. When dealing with a large project. Header only libraries do affect compile times in a quite measurable way. We just tolerate it because boost is so useful.

Additionally, there are many things which cannot be done in headers only (even boost has libraries you need to link to for certain parts such as threads, filesystem, etc). A Primary example is that you cannot have simple global objects in header only libs (unless you resort to the abomination that is a singleton) as you will run into multiple definition errors. NOTE: C++17's inline variables will make this particular example doable in the future.

As a final point, when using boost as an example of header only code, a huge detail often gets missed.

Boost is library, not user level code. so it doesn't change that often. In user code, if you put everything in headers, every little change will cause you to have to recompile the entire project. That's a monumental waste of time (and is not the case for libraries that don't change from compile to compile). When you split things between header/source and better yet, use forward declarations to reduce includes, you can save hours of recompiling when added up across a day.

Community
  • 1
  • 1
Evan Teran
  • 80,654
  • 26
  • 169
  • 231
  • 17
    I'm pretty sure that's where he's getting it from. Whenver this comes up he brings up templates. His argument is roughly that you should do all code this way for consistency. – T.E.D. Feb 24 '09 at 20:30
  • 14
    that's a poor argument he's making, stick to your guns :) – Evan Teran Feb 24 '09 at 20:58
  • 11
    Template definitions can be in CPP files if the "export" keyword is supported. That's a dark corner of C++ that is usually not even implemented by most compiles, to the best of my knowledge. – Andrei Taranchenko Feb 24 '09 at 20:58
  • There is also explicit instantiation which lets you not have all the code in the header as well (only useful if you know all the possible instantiations you will need). – Evan Teran Feb 24 '09 at 21:01
  • 2
    See the bottom of this answer (the top is somewhat convoluted) for an example: http://stackoverflow.com/questions/555330/templates-use-forward-declarations-to-reduce-compile-time/555349#555349 – Evan Teran Feb 24 '09 at 21:04
  • 3
    It starts being meaningful to this discussion at "Hooray, no linker errors." – Evan Teran Feb 24 '09 at 21:05
  • Given that my question boiled down to what the general consensus was, and this answer seems to have garnered the majority of all votes cast, and I have yet to se another contradict it, I'm accepting it. – T.E.D. Feb 25 '09 at 15:02
  • 1
    Even in template headers, it's a good idea to actually implement the code in another header and #include it at the bottom, just to separate stuff. – rlbond Jun 12 '09 at 18:03
  • 1
    @rlbond: Better yet, include it in the .cpp file that specifically uses the template implementations instead of the header. I split my templates into a .hpp and an .inl file. Other headers only include the .hpp, and then the .cpp file has to include the .inl. Improves my compile time much the same way as .cpp/.hpp separation, causing less recompilations. – Zoomulator Jan 16 '13 at 11:41
  • 2
    -1. You don't actually justify, "However, this should only be done when dealing with templates as it is the only way to do it when dealing with them." Actually I think templates invalidate your entire point - libraries like boost are nearly header-only, yet compile times did not explode, rivers did not run with blood, etc. In fact, life just went on, raising the question, why not just code in headers all the time? Maybe there's a legitimate answer to that but you haven't posted it here. – djechlin Jul 22 '13 at 12:42
  • @djechlin, actually if you search around, you will see quite a lot of people trying to find a way to reduce compile times when dealing with boost. For example: http://stackoverflow.com/questions/2258967/how-to-reduce-compilation-times-with-boost-asio, which is seeing a 14s compile of a single 1K file with boost included. 14s may not be "exploding" to you, but it is certainly a *lot* longer than typical and can add up quite quickly. When dealing with a large project. Header only library do effect compile times in a quite measurable way. We just tolerate it because boost is so useful. – Evan Teran Jul 23 '13 at 17:12
  • @djechlin, additionally, there are many things which cannot be done in headers only (even boost has libraries you need to link to for certain parts such as threads, filesystem, etc). Primarily, you cannot have simple global objects in header only libs (unless you resort to the abomination that is a singleton) as you will run into multiple definition errors. – Evan Teran Jul 23 '13 at 17:15
  • 1
    @djechlin,as a final point, you missed a huge detail. Boost is **library**, not user level code. so it doesn't change that often. In user code, if you put everything in headers. Every little change will cause you to have to recompile the **entire** project. That's a monumental waste of time (and is not the case for libraries that don't change from compile to compile). When you split things between header/source and better yet, use forward declarations to reduce includes, you can save **hours** of recompiling when added up across a day. – Evan Teran Jul 23 '13 at 17:20
  • 1
    @EvanTeran you should add that to your answer, then. – djechlin Jul 23 '13 at 17:25
  • @djechlin, if you insist :-) – Evan Teran Jul 23 '13 at 18:39
  • 1
    Circular object relationships are possible in header only code by making proper use of interfaces, I think. – TobiMcNamobi Oct 12 '16 at 09:15
  • @TobiMcNamobi, It's been a while, but yes, you are right that by using forward declarations and out of line definitions of some functions, you can have circular relationships in header only libraries. I will adjust that aspect of my answer :-) – Evan Teran Oct 12 '16 at 15:24
  • @EvanTeran Then again I wonder if it is possible to reduce dependencies by proper interfaces so that compile time is bearable. In a header only library *or* in a (near to) header only executable. And reducing dependencies is a good thing anyways ... – TobiMcNamobi Oct 13 '16 at 08:58
  • It's dummy but hey, it is another reason why you want to place your code in header files, I usually have a project called SnippetsCpp in which I put snippets for later reference, for example: draw_rectangle.h, fibonacci_algo.h. Then in the main.cpp I included all my header files and show a menu to the user to pick which demo to run. The idea is to include header files with snippets which looks less ugly than including cpp files, can you tell me your opinion on if it is ok with 'my approach' ? – Melardev Apr 04 '19 at 08:59
175

The day C++ coders agree on The Way, lambs will lie down with lions, Palestinians will embrace Israelis, and cats and dogs will be allowed to marry.

The separation between .h and .cpp files is mostly arbitrary at this point, a vestige of compiler optimizations long past. To my eye, declarations belong in the header and definitions belong in the implementation file. But, that's just habit, not religion.

Yes - that Jake.
  • 15,710
  • 14
  • 68
  • 94
31

Code in headers is generally a bad idea since it forces recompilation of all files that includes the header when you change the actual code rather than the declarations. It will also slow down compilation since you'll need to parse the code in every file that includes the header.

A reason to have code in header files is that it's generally needed for the keyword inline to work properly and when using templates that's being instanced in other cpp files.

Laserallan
  • 10,434
  • 9
  • 39
  • 63
  • 4
    "it forces recompilation of all files that includes the header when you change the actual code rather than the declarations" I think this is the most genuine reason; also goes with the fact that declarations in headers change less frequently than the implementation in .c files. – Ninad Feb 18 '13 at 10:13
22

What might be informing you coworker is a notion that most C++ code should be templated to allow for maximum usability. And if it's templated, then everything will need to be in a header file, so that client code can see it and instantiate it. If it's good enough for Boost and the STL, it's good enough for us.

I don't agree with this point of view, but it may be where it's coming from.

JohnMcG
  • 8,283
  • 5
  • 36
  • 49
  • I think you are right about this. When we discuss it he is always using the example of templates, where you more or less *have* to do this. I disagree with the "have to" as well, but my alternatives are rather convoluted. – T.E.D. Feb 24 '09 at 20:27
  • 1
    @ted - for templated code you do need to put the implementation in the header. The 'export' keyword allows a compiler to support separation of declaration and definition of templates, but support for export is prettymuch non-existant. http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1426.pdf – Michael Burr Feb 24 '09 at 20:52
  • *A* header, yes, but it doesn't have to be the same header. See unknown's answer below. – T.E.D. Feb 24 '09 at 22:37
  • That makes sense, but I can't say I've come across that style before. – Michael Burr Feb 25 '09 at 00:05
14

I think your co-worker is smart and you are also correct.

The useful things I found that putting everything into the headers is that:

  1. No need for writing & sync headers and sources.

  2. The structure is plain and no circular dependencies force the coder to make a "better" structure.

  3. Portable, easy to embedded to a new project.

I do agree with the compiling time problem, but I think we should notice that:

  1. The change of source file are very likely to change the header files which leads to the whole project be recompiled again.

  2. Compiling speed is much faster than before. And if you have a project to be built with a long time and high frequency, it may indicates that your project design has flaws. Seperate the tasks into different projects and module can avoid this problem.

Lastly I just wanna support your co-worker, just in my personal view.

Nathan Moinvaziri
  • 5,218
  • 4
  • 24
  • 28
XU Bin
  • 241
  • 3
  • 6
  • 3
    +1. No one but you had the idea that in a header only project long compile times may hint to too much dependencies which is bad design. Good point! But can these dependencies be removed to an extent where compile time is actually short? – TobiMcNamobi Oct 12 '16 at 09:14
  • @TobiMcNamobi: I love the idea of "slacking" to get better feedback on bad design decisions. However in the case of header-only vs separately compiled, if we settle on that idea we end up with a single compilation unit and huge compile times. Even when the design is actually great. – Jo So Apr 29 '17 at 00:21
  • In other words, the separation between interface and implementation is actually a part of your design. In C, you are required to express your decisions on encapsulation through separation in header and implementation. – Jo So Apr 29 '17 at 00:23
  • 1
    I'm starting to wonder if there are any drawbacks at all to just drop headers altogether like modern languages do. – Jo So Apr 29 '17 at 00:26
13

Often I'll put trivial member functions into the header file, to allow them to be inlined. But to put the entire body of code there, just to be consistent with templates? That's plain nuts.

Remember: A foolish consistency is the hobgoblin of little minds.

Mark Ransom
  • 271,357
  • 39
  • 345
  • 578
  • Yeah, I do that too. The general rule I use seems to be something along the lines of "if it fits on one line of code, leave it in the header". – T.E.D. Feb 24 '09 at 22:46
  • What happens when a library provides the body of a template class `A` in a cpp file, and then the user wants an `A`? – jww Feb 06 '17 at 17:48
  • @jww I didn't state it explicitly, but template classes should be fully defined in headers so that the compiler can instantiate it with whatever types it needs. That's a technical requirement, not a stylistic choice. I think the issue in the original question is that someone decided if it was good for templates, it was good for regular classes too. – Mark Ransom Feb 06 '17 at 19:01
7

As Tuomas said, your header should be minimal. To be complete I will expand a bit.

I personally use 4 types of files in my C++ projects:

  • Public:
  • Forwarding header: in case of templates etc, this file get the forwarding declarations that will appear in the header.
  • Header: this file includes the forwarding header, if any, and declare everything that I wish to be public (and defines the classes...)
  • Private:
  • Private header: this file is a header reserved for implementation, it includes the header and declares the helper functions / structures (for Pimpl for example or predicates). Skip if unnecessary.
  • Source file: it includes the private header (or header if no private header) and defines everything (non-template...)

Furthermore, I couple this with another rule: Do not define what you can forward declare. Though of course I am reasonable there (using Pimpl everywhere is quite a hassle).

It means that I prefer a forward declaration over an #include directive in my headers whenever I can get away with them.

Finally, I also use a visibility rule: I limit the scopes of my symbols as much as possible so that they do not pollute the outer scopes.

Putting it altogether:

// example_fwd.hpp
// Here necessary to forward declare the template class,
// you don't want people to declare them in case you wish to add
// another template symbol (with a default) later on
class MyClass;
template <class T> class MyClassT;

// example.hpp
#include "project/example_fwd.hpp"

// Those can't really be skipped
#include <string>
#include <vector>

#include "project/pimpl.hpp"

// Those can be forward declared easily
#include "project/foo_fwd.hpp"

namespace project { class Bar; }

namespace project
{
  class MyClass
  {
  public:
    struct Color // Limiting scope of enum
    {
      enum type { Red, Orange, Green };
    };
    typedef Color::type Color_t;

  public:
    MyClass(); // because of pimpl, I need to define the constructor

  private:
    struct Impl;
    pimpl<Impl> mImpl; // I won't describe pimpl here :p
  };

  template <class T> class MyClassT: public MyClass {};
} // namespace project

// example_impl.hpp (not visible to clients)
#include "project/example.hpp"
#include "project/bar.hpp"

template <class T> void check(MyClass<T> const& c) { }

// example.cpp
#include "example_impl.hpp"

// MyClass definition

The lifesaver here is that most of the times the forward header is useless: only necessary in case of typedef or template and so is the implementation header ;)

Matthieu M.
  • 251,718
  • 39
  • 369
  • 642
6

To add more fun you can add .ipp files which contain the template implementation (that is being included in .hpp), while .hpp contains the interface.

As apart from templatized code (depending on the project this can be majority or minority of files) there is normal code and here it is better to separate the declarations and definitions. Provide also forward-declarations where needed - this may have effect on the compilation time.

Anonymous
  • 17,067
  • 2
  • 38
  • 63
  • That's what I took to doing with template definitions too (although I'm not sure I used the same extension...it's been a while). – T.E.D. Feb 24 '09 at 22:27
6

Generally, when writing a new class, I will put all the code in the class, so I don't have to look in another file for it.. After everything is working, I break the body of the methods out into the cpp file, leaving the prototypes in the hpp file.

EvilTeach
  • 26,577
  • 21
  • 79
  • 136
5

I personally do this in my header files:

// class-declaration

// inline-method-declarations

I don't like mixing the code for the methods in with the class as I find it a pain to look things up quickly.

I would not put ALL of the methods in the header file. The compiler will (normally) not be able to inline virtual methods and will (likely) only inline small methods without loops (totally depends on the compiler).

Doing the methods in the class is valid... but from a readablilty point of view I don't like it. Putting the methods in the header does mean that, when possible, they will get inlined.

jww
  • 83,594
  • 69
  • 338
  • 732
TofuBeer
  • 58,140
  • 15
  • 111
  • 160
4

I think that it's absolutely absurd to put ALL of your function definitions into the header file. Why? Because the header file is used as the PUBLIC interface to your class. It's the outside of the "black box".

When you need to look at a class to reference how to use it, you should look at the header file. The header file should give a list of what it can do (commented to describe the details of how to use each function), and it should include a list of the member variables. It SHOULD NOT include HOW each individual function is implemented, because that's a boat load of unnecessary information and only clutters the header file.

SeanRamey
  • 657
  • 5
  • 15
4

If this new way is really The Way, we might have been running into different direction in our projects.

Because we try to avoid all unnecessary things in headers. That includes avoiding header cascade. Code in headers will propably need some other header to be included, which will need another header and so on. If we are forced to use templates, we try avoid littering headers with template stuff too much.

Also we use "opaque pointer"-pattern when applicable.

With these practices we can do faster builds than most of our peers. And yes... changing code or class members will not cause huge rebuilds.

Virne
  • 1,165
  • 10
  • 11
2

I put all the implementation out of the class definition. I want to have the doxygen comments out of the class definition.

Jesus Fernandez
  • 1,132
  • 2
  • 10
  • 23
  • 1
    I know it's late, but downvoters (or sympathisers) care to comment why? This seems like a reasonable statement to me. We use Doxygen, and the issue certainly came up. – T.E.D. Feb 08 '11 at 14:07
2

IMHO, He has merit ONLY if he's doing templates and/or metaprogramming. There's plenty of reasons already mentioned that you limit header files to just declarations. They're just that... headers. If you want to include code, you compile it as a library and link it up.

spoulson
  • 20,523
  • 14
  • 72
  • 101
1

Doesn't that really depends on the complexity of the system, and the in-house conventions?

At the moment I am working on a neural network simulator that is incredibly complex, and the accepted style that I am expected to use is:

Class definitions in classname.h
Class code in classnameCode.h
executable code in classname.cpp

This splits up the user-built simulations from the developer-built base classes, and works best in the situation.

However, I'd be surprised to see people do this in, say, a graphics application, or any other application that's purpose is not to provide users with a code base.

Ed James
  • 9,985
  • 15
  • 68
  • 102
  • 1
    What exactly is the distinction between "Class code" and "Executable code"? – T.E.D. Feb 26 '09 at 00:03
  • As I said, it's a neural simulator: The user creates executable simulations which are built on a large number of classes that act as neurons etc. So our code is simply classes that cannot actually do anything by themselves, and the user creates the executable code that makes the simulator do stuff. – Ed James Feb 26 '09 at 13:38
  • Generally, couldn't you say "cannot actually do anything by itself" for the vast majority (if not the entirety) of most any program? Are you saying that the "main" code goes in a cpp, but nothing else does? – T.E.D. Feb 27 '09 at 15:21
  • In this situation it's a bit different. The code that we write is basically a library, and the user builds their simulations on top of this, which are actually runnable. Think about it like openGL -> you get a bunch of functions and objects but without a cpp file that can run them they're useless. – Ed James Feb 27 '09 at 15:52
0

Template code should be in headers only. Apart from that all definitions except inlines should be in .cpp. The best argument for this would be the std library implementations which follow the same rule. You would not disagree the std lib developers would be right regarding this.

  • *Which* stdlibs? GCC's `libstdc++` seems (AFAICS) to put almost nothing in `src` & almost everything in `include`, whether or not it 'must' be in a header. So I don't think this is an accurate/useful citation. Anyway, I don't think stdlibs are much of a model for user code: they're obviously written by highly skilled coders, but to be *used*, not read: they abstract away high complexity that most coders shouldn't need to think about, need ugly `_Reserved` `__names` everywhere to avoid conflicts with the user, comments & spacing are below what I'd advise, etc. They're exemplary in a narrow way. – underscore_d Sep 16 '18 at 10:50
0

I think your co-worker is right as long as he does not enter in the process to write executable code in the header. The right balance, I think, is to follow the path indicated by GNAT Ada where the .ads file gives a perfectly adequate interface definition of the package for its users and for its childs.

By the way Ted, have you had a look on this forum to the recent question on the Ada binding to the CLIPS library you wrote several years ago and which is no more available (relevant Web pages are now closed). Even if made to an old Clips version, this binding could be a good start example for somebody willing to use the CLIPS inference engine within an Ada 2012 program.

Emile
  • 143
  • 5
  • 1
    Lol. 2 years later, this is a weird way to get hold of someone. I'll check if I still have a copy, but most likely not. I did that for an AI class so I could do my code in Ada, but purposely made that project CC0 (essentially uncopyrighted) in hopes someone would shamelessly take it and do something with it. – T.E.D. Jan 15 '19 at 21:45