Why have header files and .cpp files? [closed]
Asked Answered
K

9

553

Why does C++ have header files and .cpp files?

Kimberlite answered 2/12, 2008 at 13:18 Comment(5)
Related question: #1946346Oddball
it is a common OOP paradigm,.h is a class declaration and cpp being the definition.One does not need to know how it is implemented,he/she should only know the interface.Chippy
This is the best part of c++ separating interface from implementation. It's always good rather than keeping all the code in the single file, we have interface separated. Some amount of code are always there like inline function which are part of header files. Looks good when a header file is seen displays the list of functions declared and class variables.Awhile
There are times where header files are essential for compilation--not just an organization preference or way to distribute pre-compiled libraries. Say you have a structure where game.c depends on BOTH physics.c and math.c; physics.c also depends on math.c. If you included .c files and forgot about .h files forever you would have duplicate declarations from math.c and no hope of compilation. This is what makes most sense to me why header files are important. Hope it helps someone else.Spurtle
I think it has to do with the fact that only alphanumerical characters are allowed in extensions. I dont even know if that is true, just guessingMelodrama
P
225

Well, the main reason would be for separating the interface from the implementation. The header declares "what" a class (or whatever is being implemented) will do, while the cpp file defines "how" it will perform those features.

This reduces dependencies so that code that uses the header doesn't necessarily need to know all the details of the implementation and any other classes/headers needed only for that. This will reduce compilation times and also the amount of recompilation needed when something in the implementation changes.

It's not perfect, and you would usually resort to techniques like the Pimpl Idiom to properly separate interface and implementation, but it's a good start.

Pre answered 2/12, 2008 at 13:18 Comment(10)
Not really true. The header still contains a major part of the implementation. Since when were private instance variables part of a class's interface? Private member functions? Then what the hell are they doing in the publicly visible header? And it falls further apart with templates.Openeyed
That's why I said that it's not perfect, and the Pimpl idiom is needed for more separation. Templates are a whole different can of worms - even if the "exports" keyword was fully supported in most compilers it would still me syntactic sugar rather than real separation.Rudderhead
How do other languages handle this? for example - Java? There is no header file concept in Java.Crespo
In Java the concept of "interfaces" is more strongly supported. In my eyes these interfaces are a further development of the original idea of the "header" file - containing only the 'what'.Rudderhead
@Lazer: Java is simpler to parse. The Java compiler can parse a file without knowing all the classes in other files, and check the types later. In C++ lots of constructs are ambiguous without type information, so the C++ compiler needs information about referenced types to parse a file. That's why it need headers.Conventional
@nikie: What does "ease" of parsing have to do with it? If Java had a grammar that was at least as complex as C++, it could still just use java files. In either case, what about C? C is easy to parse, yet uses both headers and c files.Buttonhook
@Lazer: Not only is Java simpler to parse, it does not have templates (Yes, it has generics, but those are not even in the running).Quota
Is there no way C++ could support merged implementation with interface? Vast majority of code using C++, such as proof of concept, tests, simple projects do not benefit from the split, and only make your code more difficult to manage because of the thrashing between the two files.Pham
Can we also achieve abstraction separating header files from implementation files ? means we want to provide our code to third party then we can also send only header files and hide our business logic.Confetti
@Openeyed they are still part of interface because class defines a particular memory model structure of defined size. And there is virtual inheritance where it does matter. C++ got storage-based memory-model, not type-based, like java virtual machine. Java isn't executed on any real hardware, thus it got more abstract.Rabid
S
690

C++ compilation

A compilation in C++ is done in 2 major phases:

  1. The first is the compilation of "source" text files into binary "object" files: The CPP file is the compiled file and is compiled without any knowledge about the other CPP files (or even libraries), unless fed to it through raw declaration or header inclusion. The CPP file is usually compiled into a .OBJ or a .O "object" file.

  2. The second is the linking together of all the "object" files, and thus, the creation of the final binary file (either a library or an executable).

Where does the HPP fit in all this process?

A poor lonesome CPP file...

The compilation of each CPP file is independent from all other CPP files, which means that if A.CPP needs a symbol defined in B.CPP, like:

// A.CPP
void doSomething()
{
   doSomethingElse(); // Defined in B.CPP
}

// B.CPP
void doSomethingElse()
{
   // Etc.
}

It won't compile because A.CPP has no way to know "doSomethingElse" exists... Unless there is a declaration in A.CPP, like:

// A.CPP
void doSomethingElse() ; // From B.CPP

void doSomething()
{
   doSomethingElse() ; // Defined in B.CPP
}

Then, if you have C.CPP which uses the same symbol, you then copy/paste the declaration...

COPY/PASTE ALERT!

Yes, there is a problem. Copy/pastes are dangerous, and difficult to maintain. Which means that it would be cool if we had some way to NOT copy/paste, and still declare the symbol... How can we do it? By the include of some text file, which is commonly suffixed by .h, .hxx, .h++ or, my preferred for C++ files, .hpp:

// B.HPP (here, we decided to declare every symbol defined in B.CPP)
void doSomethingElse() ;

// A.CPP
#include "B.HPP"

void doSomething()
{
   doSomethingElse() ; // Defined in B.CPP
}

// B.CPP
#include "B.HPP"

void doSomethingElse()
{
   // Etc.
}

// C.CPP
#include "B.HPP"

void doSomethingAgain()
{
   doSomethingElse() ; // Defined in B.CPP
}

How does include work?

Including a file will, in essence, parse and then copy-paste its content in the CPP file.

For example, in the following code, with the A.HPP header:

// A.HPP
void someFunction();
void someOtherFunction();

... the source B.CPP:

// B.CPP
#include "A.HPP"

void doSomething()
{
   // Etc.
}

... will become after inclusion:

// B.CPP
void someFunction();
void someOtherFunction();

void doSomething()
{
   // Etc.
}

One small thing - why include B.HPP in B.CPP?

In the current case, this is not needed, and B.HPP has the doSomethingElse function declaration, and B.CPP has the doSomethingElse function definition (which is, by itself a declaration). But in a more general case, where B.HPP is used for declarations (and inline code), there could be no corresponding definition (for example, enums, plain structs, etc.), so the include could be needed if B.CPP uses those declaration from B.HPP. All in all, it is "good taste" for a source to include by default its header.

Conclusion

The header file is thus necessary, because the C++ compiler is unable to search for symbol declarations alone, and thus, you must help it by including those declarations.

One last word: You should put header guards around the content of your HPP files, to be sure multiple inclusions won't break anything, but all in all, I believe the main reason for existence of HPP files is explained above.

#ifndef B_HPP_
#define B_HPP_

// The declarations in the B.hpp file

#endif // B_HPP_

or even simpler (although not standard)

#pragma once

// The declarations in the B.hpp file
Sharper answered 2/12, 2008 at 13:18 Comment(10)
You still have to copy paste the signature from header file to cpp file, don't you?Canonry
@Canonry : You still have to copy paste the signature from header file to cpp file, don't you? : No need. As long as the CPP "includes" the HPP, the precompiler will automatically do the copy-paste of the contents of the HPP file into the CPP file. I updated the answer to clarify that.Sharper
Thanks, your copy/paste notion was helpful. But your point "It won't compile because A.cpp has no way to know "doSomethingElse" exists" seems wrong to me. While compiling A.cpp, compiler knows the types of arguments and return value of doSomethingElse from the call itself; it can assume that doSomethingElse is defined in another module and rely on linker to fill in the dependency (or return error if it can't find its definition or types of arguments/return value are incompatible in A.cpp and B.cpp). I still don't get the necessity of headers. Seems, they're just a pretty ugly arbitrary design.Limn
@Bob : While compiling A.cpp, compiler knows the types of arguments and return value of doSomethingElse from the call itself. No, it doesn't. It does only know the types provided by the user, which will, half the time, won't even bother to read the return value. Then, implicit conversions happen. And then, when you have the code: foo(bar), you can't even be sure foo is a function. So the compiler has to have access to the information in the headers to decide if the source compiles correctly, or not... Then, once the code is compiled, the linker will just link together functions calls.Sharper
@Bob : [continuing] ... Now, the linker could do the work done by the compiler, I guess, which would then make your option possible. (I guess this is the subject of the "modules" proposition for the next standard). Seems, they're just a pretty ugly arbitrary design. : If C++ had been created in 2012, indeed. But remember C++ was built upon C in the 1980s, and at that time, constraints were quite different at that time (IIRC, it was decided for adoption purposes to keep the same linkers than C's).Sharper
@Sharper Thanks for explanation and notes, paercebal! Why can't I be sure, that foo(bar) is a function - if it's obtained as a pointer? In fact, speaking of bad design, I blame C, not C++. I really don't like some constraints of pure C, such as having header files or having functions return one and only one value, while taking multiple arguments on input (doesn't it feel natural to have input and output behave in a similar manner; why multiple arguments, but single output?) :)Limn
@Bobo : Why can't I be sure, that foo(bar) is a function : foo could be a type, so you would have a class constructor called. In fact, speaking of bad design, I blame C, not C++ : I can blame C for a lot of things, but having been designed in the 70's won't be one of them. Again, constraints of that time... such as having header files or having functions return one and only one value : Tuples can help mitigate that, as well as passing arguments by reference. Now, what would be the syntax to retrieve returned multiple values, and would it be worth it to change the language?Sharper
The reply should have been chosen as the answer of this post. The original is good as well, but this reply covers everything basically.Immunochemistry
Why couldn't you just include B.CPP into A.CPP?Unmindful
@Lazer wayback machine link to "Organizing Code Files in C and C++ " web.archive.org/web/20100124195524/http://www.gamedev.net/… / current link: gamedev.net/articles/programming/…Sinless
P
225

Well, the main reason would be for separating the interface from the implementation. The header declares "what" a class (or whatever is being implemented) will do, while the cpp file defines "how" it will perform those features.

This reduces dependencies so that code that uses the header doesn't necessarily need to know all the details of the implementation and any other classes/headers needed only for that. This will reduce compilation times and also the amount of recompilation needed when something in the implementation changes.

It's not perfect, and you would usually resort to techniques like the Pimpl Idiom to properly separate interface and implementation, but it's a good start.

Pre answered 2/12, 2008 at 13:18 Comment(10)
Not really true. The header still contains a major part of the implementation. Since when were private instance variables part of a class's interface? Private member functions? Then what the hell are they doing in the publicly visible header? And it falls further apart with templates.Openeyed
That's why I said that it's not perfect, and the Pimpl idiom is needed for more separation. Templates are a whole different can of worms - even if the "exports" keyword was fully supported in most compilers it would still me syntactic sugar rather than real separation.Rudderhead
How do other languages handle this? for example - Java? There is no header file concept in Java.Crespo
In Java the concept of "interfaces" is more strongly supported. In my eyes these interfaces are a further development of the original idea of the "header" file - containing only the 'what'.Rudderhead
@Lazer: Java is simpler to parse. The Java compiler can parse a file without knowing all the classes in other files, and check the types later. In C++ lots of constructs are ambiguous without type information, so the C++ compiler needs information about referenced types to parse a file. That's why it need headers.Conventional
@nikie: What does "ease" of parsing have to do with it? If Java had a grammar that was at least as complex as C++, it could still just use java files. In either case, what about C? C is easy to parse, yet uses both headers and c files.Buttonhook
@Lazer: Not only is Java simpler to parse, it does not have templates (Yes, it has generics, but those are not even in the running).Quota
Is there no way C++ could support merged implementation with interface? Vast majority of code using C++, such as proof of concept, tests, simple projects do not benefit from the split, and only make your code more difficult to manage because of the thrashing between the two files.Pham
Can we also achieve abstraction separating header files from implementation files ? means we want to provide our code to third party then we can also send only header files and hide our business logic.Confetti
@Openeyed they are still part of interface because class defines a particular memory model structure of defined size. And there is virtual inheritance where it does matter. C++ got storage-based memory-model, not type-based, like java virtual machine. Java isn't executed on any real hardware, thus it got more abstract.Rabid
O
107

Because C, where the concept originated, is 30 years old, and back then, it was the only viable way to link together code from multiple files.

Today, it's an awful hack which totally destroys compilation time in C++, causes countless needless dependencies (because class definitions in a header file expose too much information about the implementation), and so on.

Openeyed answered 2/12, 2008 at 13:18 Comment(2)
I wonder why header files (or whatever was actually needed for compilation/linking) were not simply "auto-generated"?Amerind
it waay predates K&R C. Almost every language before that used same paradigms, an exception would be languages like Pascal which had special compilation unit called "unit" which was both header and implementation in one and main one called "program". It's all about dividing program into pieces of code manageable by compiler and to reduce compile time\allow incremental compilation.Rabid
D
59

Because in C++, the final executable code does not carry any symbol information, it's more or less pure machine code.

Thus, you need a way to describe the interface of a piece of code, that is separate from the code itself. This description is in the header file.

Dandy answered 2/12, 2008 at 13:18 Comment(0)
A
24

Because C++ inherited them from C. Unfortunately.

Aldredge answered 2/12, 2008 at 13:18 Comment(4)
Why inheritance of C++ from C is unfortunate?Marduk
How can this be an answer?Multiform
@ShuvoSarker because as thousands of languages have demonstrated, there is no technical explanation for C++ making programmers write function signatures twice. The answer to "why?" is "history".Chalmer
@Boris funny, that C actually didn't require to write them twice. ANd C originally didn't need prototypes at all, because it was running on platforms that allowed such implementation.They didn't even have stack registers, "stack" was just an area of memory managed by produced code. It's C++ thing and modern platforms shifted to register-based or mixed way of calling functions, so separate prototype IS required if we hide implementation and if we can overload. Quite a number of classic (Fortran, Pascal) and modern languages do as well. Absence of such is usually a signature of interpreterRabid
C
16

Because the people who designed the library format didn't want to "waste" space for rarely used information like C preprocessor macros and function declarations.

Since you need that info to tell your compiler "this function is available later when the linker is doing its job", they had to come up with a second file where this shared information could be stored.

Most languages after C/C++ store this information in the output (Java bytecode, for example) or they don't use a precompiled format at all, get always distributed in source form and compile on the fly (Python, Perl).

Capacitate answered 2/12, 2008 at 13:18 Comment(2)
Wouldn't work, cyclic references. I.e.you can't build a.lib from a.cpp before building b.lib from b.cpp, but you can't build b.lib before a.lib either.Genniegennifer
Java solved that, Python can do it, any modern language can do it. But at the time when C was invented, RAM was so expensive and scarce, it just wasn't an option.Capacitate
K
8

It's the preprocessor way of declaring interfaces. You put the interface (method declarations) into the header file, and the implementation into the cpp. Applications using your library only need to know the interface, which they can access through #include.

Kingston answered 2/12, 2008 at 13:18 Comment(0)
T
6

Often you will want to have a definition of an interface without having to ship the entire code. For example, if you have a shared library, you would ship a header file with it which defines all the functions and symbols used in the shared library. Without header files, you would need to ship the source.

Within a single project, header files are used, IMHO, for at least two purposes:

  • Clarity, that is, by keeping the interfaces separate from the implementation, it is easier to read the code
  • Compile time. By using only the interface where possible, instead of the full implementation, the compile time can be reduced because the compiler can simply make a reference to the interface instead of having to parse the actual code (which, idealy, would only need to be done a single time).
Traject answered 2/12, 2008 at 13:18 Comment(2)
Why couldn't library vendors just ship a generated "header" file? A pre-processor free "header" file should give much better performance (unless the implementation was really broken).Foliaceous
I think its irrelevant if the header file is generated or hand written, the question wasn't "why do people write header files themselves?", it was "why do we have header files". The same goes for preprocessor free headers. Sure, this would be faster.Ingesta
F
-5

Responding to MadKeithV's answer,

This reduces dependencies so that code that uses the header doesn't necessarily need to know all the details of the implementation and any other classes/headers needed only for that. This will reduce compilation times, and also the amount of recompilation needed when something in the implementation changes.

Another reason is that a header gives a unique id to each class.

So if we have something like

class A {..};
class B : public A {...};

class C {
    include A.cpp;
    include B.cpp;
    .....
};

We will have errors, when we try to build the project, since A is part of B, with headers we would avoid this kind of headache...

Flipflop answered 2/12, 2008 at 13:18 Comment(1)
This is specifically called abstraction am I right ?Nestorius

© 2022 - 2024 — McMap. All rights reserved.