Header vs ..Body? Newbie C++ Questions

Handmade Hero is awesome and you've made it awesome, Casey. Preordered after reading the concept and watching the first videos.

I have a couple questions I'm hoping someone could answer for me. I have many more videos to watch in your series thus far so I'm not sure if this was ever answered or even asked.

Header is obviously a ".h" file and I say "Body" meaning the ".cpp" file.

When including other headers, when do you know you should include it within another class header file or body file? What happens if they both include the file? Assuming I had a header file "foo.h," created another class with header file "bar.h" and body "bar.cpp"; when do you know to include "foo.h" in the header "bar.h" or body "bar.cpp" or does it really matter?

Another question I have is creating functions in the header, for example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// foo.h
class FOO
{
public:

	int ID;

	void SetID(const int NewID){ ID = NewID; }
	int GetID() const{ return ID; }
}


When should you create functions in the body instead of the header? What if I was to put everything into the header, is that okay? What if all was in the body?

One last question regarding "const," which I had also written above. If the variable isn't a pointer does it really matter if you use const? For clarity:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// this useless?
const int GetID() const{ return ID; }

// const only this?
const int GetID() const{ return *ID; }

// const this?
int GetID() const{ return ID; }
// does it really matter and I can just always use this?
int GetID(){ return ID; }


I hope my question aren't confusing and I thank anyone taking the time to help me out.

Edited by Paul on Reason: clarity
Assuming I had a header file "foo.h," created another class with header file "bar.h" and body "bar.cpp"; when do you know to include "foo.h" in the header "bar.h" or body "bar.cpp" or does it really matter?


You would include the .h file, if you used the class in bar. Ok, so there are two different reasons I can name off the top of my head. Here they are.

1. The implementation of bar used foo, i.e you need something in the .cpp of bar, so you would include it there.
1
2
3
4
5
6
//bar.cpp
#include "foo.h"
Bar::DoStuff() {
    Foo foo;
    foo.dostuff();
}

2. The declaration of Bar needs to reference Foo, you would include it in bar.h
1
2
3
4
5
//bar.h
#include "foo.h"
class Bar {
    Foo* foo;
}

If you include foo.h in bar.h, you do not need to include it again in bar.cpp.


When should you create functions in the body instead of the header? What if I was to put everything into the header, is that okay? What if all was in the body?


I don't know all the nuances of C and C++ but I know that if the function is inline you have to put the function implementation where the other file can see it. It can't be in another translation unit. I'm sure there's other reasons, but I don't know.

On the last question, declaring a parameter passed by value const doesn't do anything. I mean, the reason why you'd use const there is to tell the caller the value won't change, and since it was passed by value, there won't be a change, since in the function a copy of the parameter will be created. Also, there is no reason to return a const like you are doing either. There are more nuances to using const, Im sure someone else can explain much better than I.

Honestly you should think about why you are using const anyway, don't throw it around just because. That goes for really anything. Especially getter and setter methods, those are my pet peeves. I know it was just a simple example, but still.

Edited by Justin on
Well, there are really two answers to this question, depending on you are programming the way I program or the way most C++ people program :)

If you program the way I program, you never type "const", and you put functions wherever you want and include whatever you want however you want. The reason for not using "const" is that I don't find it to help me catch any errors, so it's just wasted work. The reason for including whatever, wherever, is because I tend to compile things as one or two compilation units, like in Handmade Hero, so _everything is effectively one file to the compiler anyway_. So I think of everything as just one big file, and the actual .h/.cpp files are just logical ways of separating code so they stay easy to find and work with mentally - but they all get #included into one big file for compilation, so it literally doesn't matter how you want to organize your #includes, or what goes into .h's vs. .cpp's. As long as things appear in the right order (ie., things are declared before they are used), any #include structure that you prefer is fine.

If you program the way most C++ programmers program, then you do use "const" all over the place, and the idea here is to try to have the compiler catch bugs where you are writing to something you are not supposed to write to. So in your example, yes, you may have to "constify" something even if it is not a pointer, because you can only call const member functions on a const object. So if someone wants to get the ID, and they have a const reference to the object, they can't call the non-const version because the compiler will consider that an error.

And if you program like most C++ programmers, your .h/.cpp structure will be very regular as well. All the class definitions go in a .h file, usually one per class, and all the functions for that class go into the .cpp file that has the same name as the .h in which the class is defined. You then #include the .h's anywhere you need to, and you never #include .cpp's at all, you just pass all the .cpp's to the compiler and they get compiled individually.

Hope that helps,
- Casey
Sweet, thanks for the answers guys!

I imagine everything included into a single file for compilation or during compilation as well and that was going to be one of my next questions. If I had hundreds of classes (.h/.cpp for each) and had a single header file that #included everything that every class would ever need to communicate between each other; how horrible is that for the compiler or performance?

I personally want to stray away from "const" because it's just more words to type when you already have to type so much when programming. I was just wondering if it was a compiler performance benefit using "const" in functions that you knew, in that situation, the value is passed by value but will not be changed.

Helped tons, Casey. I come from a long programming history, obviously in languages outside of C, made the mistake[?] of learning C# first in college but had the reasons, and have been slowly backed into a corner to start learning AND using C. Several sites/videos later it was only your videos that made everything start making more sense to me and gave me a giant boost in confidence and motivation to just dive right into everything.



insanoflex; Thank you very much. In your first #include foo example this would be overall better than having a global header that just included everything in your project? This is basically the same question as my first question in this reply.

I didn't know that about inline functions, I was wondering why I kept getting errors whenever I tried to use them, and I kept wanting to do something like:
1
inline int GetID(){ return ID; }


I don't know.. just felt good typing that in a single line and be done with the function and purpose.

Overall I thought "const" had some kind of benefit behind the scenes and was looking for clarity on the subject. What I had in mind was that the compiler would decide that:
1
virtual void SetID(const int NewID){ ID = NewID; }


Would be like telling the compiler "hey, not a pointer, but I won't be changing this value at ALL bro.. just reference the value in memory and don't create a useless variable please" or something like that. Probably doesn't matter either way but what can I say.. I ask newbish things.

I understood the purpose for using "const" with pointers but you've helped me clear things up.

Thanks fellas!
I was going to explain how including files works, but I realized that my calling in life isn't teaching. In fact it's so far from it I can't even explain a simple concept hahahaha.
What I do is, I generally include as little as I need to in each compilation unit. But, including everything in one file is how windows works. If you want to use a windows function, you should only include the windows.h file, excluding certain libraries like xinput and directx.
All good, insanoflex, I appreciate the help you've given, and I understand that I should only include what I need.

Thanks!
The problem with const is that the C++ spec is busted, so there's no real way for the compiler to optimize based on const. There is one specific case where it can help, and it's this:

1
2
3
    const float X = 3.14f;
    DoSomething(&X);
    return(asin(0.1f*sin(atan(0.5f*tan(X)))));


Namely, if a value that could be modified by a subroutine is explicitly declared const, then the compiler knows it doesn't have to actually re-read the value after the call. Normally this doesn't actually matter for optimization, but in a case like the one above where a ton of stuff is done to the value, the compiler may be able to drastically simplify an expression by precomputing values, etc. Of course, in the case I presented, it might be wishful thinking because I don't know how much trig compilers actually will optimize in practice, but, you know, it's theoretically possible :)

Unfortunately, most people think there is a bunch of optimization you can do with const, but they are usually wrong. For example this:

1
2
3
4
5
6
7
float Foo(float const *TheThing)
{
    float X = *TheThing*sin(*TheThing);
    DoSomething(X, TheThing);
    float Y = *TheThing*sin(*TheThing);
    return Y;
} 


People typically think that the compiler can count on the value of TheThing not changing because it is declared const, but that is not what the spec actually says for this case, so actually the compiler cannot optimize out the computation of Y by just using X. What the spec actually says here is that this function can not modify TheThing, but even if DoSomething is also declared as a const pointer, it can still be casted away inside DoSomething and be legal. So, the compiler has to assume that the value can change.

- Casey
Very interesting, Casey. Thank you greatly for your replies.

In your opinion and from experience, for optimization reasons, is it bad to "#include" a lot, or all, of your classes if you actually wanted every class to be able to communicate with each other? Just a curiosity, I don't exactly plan to do that, I plan to continue what I've done, as well as what was advised; to include what I need, where I need it.

If I had a ".h" and ".cpp" for A through Z, and a header called "globals.h" that had "#include "B.h"" through Z, and in A I used "#include "globals.h""; is that bad? Any idea how B would handle using "#include "globals.h"" since that header has "#include "B.h""?

Thanks again everyone.

Edited by Paul on Reason: attempted clarity
If your file structure means that a file will be included twice, the compiler will have no qualms about including it twice. This usually means you'll get name collisions when the second-time file tries to define variables/functions/macros that already exist.

The usual solution to this is what are called Include Guards, where you define a certain macro (usually a CAPITALIZATION of the name of the file with _ instead of ., for example A_H) when the file is included for the first time. You then surround the contents of the file with an #if !defined(A_H) and #endif at the end, so they only appear if that symbol isn't defined.

You can see in Handmade Hero that casey's default template for new .h files does this, so he might have explained it once at the beginning but it hasn't really come up again. It is generally good practice to just include guard all of your headers regardless of whether or not you think they'll be included multiple times, just so that it doesn't matter if they are for some reason. This is especially true in unity-build type situations where everything ends up in the same translation unit.

Edited by Andrew Chronister on
Awesome, thanks ChronalDragon!
As with many things, 3dmasons, it's hard to say whether something is "bad" out of context.

In a "single-translation-unit build", everything is included together and everything can talk to each other, and there is no speed penalty for this (in fact you are getting a speed boost). However, in standard many-translation-unit builds, you may have hundreds or even thousands of CPP files, often one per class, and in this case it can become prohibitively expensive to #include everything everywhere because touching a single H file will recompile every CPP in the entire project, which will take minutes or even hours.

And sadly, I'm not exaggerating about that. There are many major CPP builds out there in the wild that take longer than an episode of Handmade Hero.

So when you've got that kind of a fudge-up on your hands, being judicious with includes becomes important to minimize the number of CPP files that need to be recompiled (and linked, if you've got an incremental linker).

But, certainly I advocate for never, ever, EVER having a compile time above ten seconds, so I would say it's best just to not get into that situation in the first place.

- Casey