Why put a class declaration and definition in two separate files in C++?
Asked Answered
M

7

20

I'm just wondering, what is the whole point of separating classes into an .h and a .cpp file? It makes it harder to edit, and if your class won't be compiled into a .lib or .dll for outside use, what's the point?

Edit: The reason I'm asking is that the Boost libraries put everything in an .hpp file, (most of the libraries anyways), and I wanted to know why it is separated in most of the other code that I see.

Manipulator answered 17/5, 2009 at 2:9 Comment(0)
K
26

C++ has something called the One Definition Rule. It means that (excluding inline functions), definitions can only appear in one compilation unit. Since C++ header files are just "copy and pasted" at every include file, now you are putting definitions in multiple places if you just put the definitions in header files.

Of course, you may say, why not make everything inline. Well, if the compiler respects your inline suggestion, code for long functions will be replicated at every call site, making your code excessively large, and possibly causing thrashing, cache issues, and all sorts of unfun stuff.

On the other hand, if the compiler does not listen to you, and doesn't inline anything, now you have 2 problems: 1) you don't know which translation unit got your classes definitions, and 2) the compiler still has to wade through your definitions every time you #include them. Moreover, there's no easy way to make sure you haven't accidentally defined the same method twice, in 2 different headers, differently.

You also get a circular dependency issue. For a class to invoke another class's method, that class needs to be declared first. So if 2 classes need to invoke each other's methods, each must be declared before either can be defined. There is no way to do this with declarations and definitions in one file.

Really, it's how the language and parser were built. It's a pain, but you just have to deal with it.

Kenzi answered 17/5, 2009 at 2:17 Comment(1)
@CharlieMartin: "definitions can only appear in one compilation unit" that's not a real problem, many other languages don't have headers and work just fine.Artificiality
E
6

Well, one of the benefits of having the code this way is that it reduces compile time.

Let's say you have these files on your project:

  • a.h
  • a.cpp
  • b.cpp

If you already have a.cpp compiled into an object file a.o, then if you include a.h in b.cpp, compilation should be quicker because parser won't have to deal with the whole declaration/definition of a.

Epigenous answered 17/5, 2009 at 2:15 Comment(1)
Still don't understand why we need .h and separate declaration from definition - objective file a.o consists everything we need for compiling and linking with b.cpp!Badr
H
4

Boost doesn't inline all of it's code; it inlines template definitions for classes it expects its consumers to instantiate, like shared_ptr. Many libraries have sections that need to be compiled separately, like boost::serialization and program_options.

Inlining can have severe negative effects as the size of your code base increases. It increases the coupling between your components, not to mention nuking your compile time (which boost does for plenty of other reasons :). Effectively, all of your translational units would have almost a complete copy of the program, and a tiny change would cause you to rebuild/retest everything. On some projects, this could take many, many hours.

I've never really noticed it being harder to edit; in my experience, it makes it easier because of the clear separation of interface and implementation, and I know which file to go to find what I'm looking for.

Hexachord answered 17/5, 2009 at 3:46 Comment(1)
Good answer! I'd add only that unfortunately the separation of interface and implementation is not as clear as one would wish it to be, since part of implementation leaks into the header in the form of private data fields (because otherwise the compiler wouldn't know the size of the class). The pimpl idiom is used to address this issue.Shumway
I
2

Because even within your DLL other classes will use your class. Those files must see the class declaration at compile time, by including the .h. They must not see the definition or there will be multiple definitions of the class functions.

Idaidae answered 17/5, 2009 at 2:17 Comment(0)
A
2

Your edit re: Boost makes an important distinction. Template classes are almost always defined in headers because of the way the compiler and linker work in the current C++ standard. You will find most template libraries (not just Boost) are implemented in header files for the same reason.

Adara answered 17/5, 2009 at 3:35 Comment(0)
R
0

In C++, separate compilation of code modules (.c or .cpp files) require the function prototypes to be defined prior to usage. If you want to use classes or methods defined somewhere else, you have to import the .h files to get their definition. At the end, the linker makes sure all promises made in the .h files can be fulfilled by all c/cpp files.

Also, it allows to created whole frameworks such as boost only by defining .h files.

Rattail answered 17/5, 2009 at 2:19 Comment(1)
Boost mostly comprises header files since relying heavily on c++ templates (which implies to put a whole class definition in its header when it is templated for instance). As far as I remember some part of this framework has cpp file, the one which does not rely on c++ templates: the thread library for instance.Granth
L
-1

Because in most cases, you'll want to use the class somewhere besides the file in which you implement it. If you make the whole program in one file, you don't need the separation.

You hardly ever want to write a C++ program all in one file.

Lovesome answered 17/5, 2009 at 2:14 Comment(7)
I meant putting the whole class definition in a .h and including it, while protecting it with header guardsManipulator
what happens if you include that .h file in more than one place in the same executable? Ans: you end up with multiple definitions of the same functions. — The real point here is that you can do all sorts of goofy things with the rules, but they nearly always turn out not to work as well in practice as the normal ways.Lovesome
@CharlieMartin: "multiple definitions of the same functions" that's not the real problem. Many other languages don't have headers and work just fine.Artificiality
@MooingDuck Name me one that can have the same function (name and signature) defined in two places to be linked into the same executable. Or read some of the other answers.Lovesome
@CharlieMartin: I mean there exist languages like java, where you can compile all the classes separately. You don't end up with multiple definitions of the same functions because you don't have to declare anything. The root of the OP's question is "why do we need declarations and headers, when almost no other language requires this complexity"Artificiality
Yes there are indeed. Java’s model for that is a little goofy too But the need to separate off the header files where is one of the things that James wanted to eliminate. But Java won’t let you get away with having more than one identical name in the global name space eitherLovesome
I like your answer Charlie. It actually deals with the question.Chapman

© 2022 - 2024 — McMap. All rights reserved.