Introduction
I think it's a bit sloppy to define a class in a header file, so I decided that I wanted to split up my class template into a header file (the class template declaration)
and source file (the class template definition). I soon realized the issue here: it would need circular dependency to define itself (which I will explain).
There's a quick and safe way to do this, and this is how I figured it out. First, you need to define the class. Here's the example we'll be using (I removed
the documentation and code so it's just bare bones). As you can see, it's just the two separate files (the header file and source file).
#ifndef INPUT_H_
#define INPUT_H_
template <class T>
class Input
{
public: Input(T test);
};
#endif /* INPUT_H_ */
template <class T>
Input<T>::Input(T stream)
{
}
Including Class Member Definitions
The first error that arises is that the class template is searching for a constructor definition (which is not in the header file as you can see).
To fix this, we create a link to the source file (just within the preprocessor definition check body):
#include "Input.cpp"
.
Now, the header file links to the source file and can successfully obtain the constructor definition.
Including Class Declarations
This is where a second problem arises; the class isn't defined in the source file (because we didn't include it and source files include resources using one-way,
linear dependency ... so the header information did not get passed to the source file). Well, that's no problem. We'll just include the header file in the source
file to get the class definition. At the top of the file, we add #include "Input.h"
.
Solving the Duplicate Definition Error
This is where we fall into a loop. The source file includes the input header file... which includes the source file. This leaves the source file being compiled
twice (which throws an error - the constructor has been defined twice). Luckily... the class template doesn't load resources from the source file (remember,
it's one-way, linear dependency). All it includes is the link to the template definition. We can get away with compiling the header file first (as long
as the #include "Input.cpp"
is there). So finally, we can fix this by adding a preprocessor definition check to stop the compiler's second attempt
at compiling the source file (as seen below).
#ifndef INPUT_H_
#define INPUT_H_
template <class T>
class Input
{
public: Input(T test);
};
#include "Input.cpp"
#endif /* INPUT_H_ */
#ifndef INPUT_CPP_
#define INPUT_CPP_
#include "Input.h"
template <class T>
Input<T>::Input(T stream)
{
}
#endif /* INPUT_CPP_ */
Conclusion
That's it. The class template is now being declared in the header file and defined in the source file. First, we included the class member definitions so the template was defined;
then, we included the class declaration so the source file could define the class; and finally, we solved our duplicate definition error by using pre-processor directives.