First, you should not put anything into headers that is not needed to be visible by any other file, other than the one that needs it. Then, let's define something we need below.
Translation Unit
A Translation Unit is the current code being compiled, and all the code included
by it, directly or indirectly. One Translation unit translates to one .o / .obj file.
Program
That's all your .o / .obj files linked together into one binary file that can be
executed to form a process.
What are the main points of having different translation units?
- Reduce dependencies, so that if you change one method of one class, you don't have to recompile all the code of your program, but only the affected translation unit. An
- Reduce possible name clashes by having translation unit local names, that are not visible by other translation unit when linking them together.
Now, how can you split your code into different translation units? The answer is there is no "so you do it!", but you have to consider it on a case-by-case basis. It's often clear, since you have different classes, which can and should be put in different translation units:
foo.hpp:
/* Only declaration of class foo we define below. Note that a declaration
* is not a definition. But a definition is always also a declaration */
class foo;
/* definition of a class foo. the same class definition can appear
in multiple translation units provided that each definition is the same
basicially, but only once per translation unit. This too is called the
"One Definition Rule" (ODR). */
class foo {
/* declaration of a member function doit */
void doit();
/* definition of an data-member age */
int age;
};
Declare some free functions and objects:
/* if you have translation unit non-local (with so-called extern linkage)
names, you declare them here, so other translation units can include
your file "foo.hpp" and use them. */
void getTheAnswer();
/* to avoid that the following is a definition of a object, you put "extern"
in front of it. */
extern int answerCheat;
foo.cpp:
/* include the header of it */
#include "foo.hpp"
/* definition of the member function doit */
void foo::doit() {
/* ... */
}
/* definition of a translation unit local name. preferred way in c++. */
namespace {
void help() {
/* ... */
}
}
void getTheAnswer() {
/* let's call our helper function */
help();
/* ... */
}
/* define answerCheat. non-const objects are translation unit nonlocal
by default */
int answerCheat = 42;
bar.hpp:
/* so, this is the same as above, just with other classes/files... */
class bar {
public:
bar(); /* constructor */
};
bar.cpp:
/* we need the foo.hpp file, which declares getTheAnswer() */
#include "foo.hpp"
#include "bar.hpp"
bar::bar() {
/* make use of getTheAnswer() */
getTheAnswer();
}
Please note that names within an anonymous namespace (as above) do not clash since they appear to be translation unit local. in reality they are not, they just have unique names so that they do not clash. if you really want (there is little reason to) translation unit local names (for example because of compatibility with c so C code can call your function) you can do it like this:
static void help() {
/* .... */
}
The ODR also says that you cannot have more than one definition of any object or non-inline function in one program (classes are types, not objects, so it doesn't apply to them). So you have to watch out not to put non-inline functions into headers, or not putting objects like "int foo;" in headers. That will cause linker errors then when the linker tries to link the translation units including those headers together.
I hope i could help you a bit. Now that was a long answer, there are indeed errors somewhere. I know that a translation unit strictly is defined another way (output of the pre-processor). But i think it would not add big value to include that into the above, and it would confuse the matter. Please feel free to slap me if you find real bugs :)