Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Placing methods in .h vs. .cpp files

I've seen code for a class placed into a separate C++, while the method definitions are placed in the header file. My 1st OOP experience is with Java, in which all the methods are placed in the class file, and I actually prefer this.

Does placing all my methods in a header file affect the assembly code generated by the compiler, or not?

And if so, is it detrimental to performance at all to place the entire code of a class in its header file?

like image 472
sj755 Avatar asked Jul 10 '26 06:07

sj755


2 Answers

The point is that complex C++ programs are created by compiling multiple objects, then linking them together. Each object typically results from compiling one implementation file (e.g. ".cpp", ".cc" etc), which may directly and indirectly include a lot of headers. Consequently, if you write a good class and put the code into the header, then that code can be included in multiple object files, and then the compiler is redundantly generating it, and further - the linker wont (and can't easily) compare the versions to see if they're equivalent and remove the redundant copies (easier if using relative addresses - "position independent code" - but that's another story). See also jalf's comment below.

So, you don't want different out-of-line functions in your headers. If they're nominally inline functions - due to use of the inline keyword or being defined inside a class - then the compiler will simply have to undertake the extra work and ensure that any out-of-line version of them is uniquely represented in the executable. But, for out of line functions the burden remains with the programmer.

Further, if you provide implementation in your headers, it's redundantly compiled for each object, and any change to the header will force a recompilation of all the depedent objects. Out-of-line functions in separate objects can be changed, that single object recompiled, then it can be linked with other pre-existing objects to form a new executable. In large-scale projects, this saves a LOT of compilation time.

like image 195
Tony Delroy Avatar answered Jul 11 '26 19:07

Tony Delroy


There're a few valid reasons for header/implementation splitting and separate compilation:
1. That may be a job requirement - for example, you're supplying a binary library + header to somebody, or your colleagues are too conservative to accept anything else.
2. Its still required to develop very large projects (say, >10M of source), because rebuilding the whole app after each modification would become painful. (But it should be still ok to compile something like jpeglib or zlib as a single module)
3. There's an opinion that its easier to use header files as reference, to look up functions and such. (But normally its better to write a proper documentation; unlike headers, bugs in documentation are less likely to affect your program)

Also, there're much more reasons to not use it anymore:
1. You'd like to avoid maintaining the duplicate code.
2. Class methods don't need forward declarations
3. Templates can only be declared in headers anyway
4. Cases where you don't need function inlining are actually fairly rare, ie calling large functions multiple times in a tight loop, but there're noinline attibutes and PGO for that. Otherwise inlining improves speed. And as to code bloat, most libraries are already huge anyway.
5. Overall, programs compiled as a single source are faster and smaller, because the compiler can do a better job.
6. Without headers, the source would be frequently around twice smaller, and compiler would be able to properly check the syntax, so you won't be able to accidentally link an extern "C" cdecl function prototype to a variable as implementation. Also overall, it would be more portable, because different linkers have different ideas about name matching.
7. Its weird, but dynamic allocation is frequently used only because of header style - dependencies could be resolved automatically by defining all the details within a single class, but people prefer to use pointers to partial class declarations instead (and then hunt memory leaks).

Now, a few bonus points for separate object modules:
4. PGO stats in gcc are generated per object module, which seems to be the only way to "benchmark" a few different operation modes with a single executable.
5. Its possible to compile different modules with different compiler options for speed optimization. There're also some compiler extensions for that, but they're not very reliable.
6. Sometimes a compiler can do something weird to another part of code when you modify something - but usually it can't propagate outside of an object module.

like image 41
Shelwien Avatar answered Jul 11 '26 20:07

Shelwien



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!