I have an example with the custom Stack implementation. As far as I understood, the .h
files should only contain declarations and the cpp
files should only contain implementations. I have found an example of a custom Stack on the cplusplus.com/stack_example and it looks something like the following.
Stack.h file
#ifndef _STACK_H_
#define _STACK_H_
#include <iostream>
#include "Exception.h"
template <class T>
class Stack {
public:
Stack():top(0) {
std::cout << "In Stack constructor" << std::endl;
}
~Stack() {
std::cout << "In Stack destructor" << std::endl;
while ( !isEmpty() ) {
pop();
}
isEmpty();
}
void push (const T& object);
T pop();
const T& topElement();
bool isEmpty();
private:
struct StackNode { // linked list node
T data; // data at this node
StackNode *next; // next node in list
// StackNode constructor initializes both fields
StackNode(const T& newData, StackNode *nextNode)
: data(newData), next(nextNode) {}
};
// My Stack should not allow copy of entire stack
Stack(const Stack& lhs) {}
// My Stack should not allow assignment of one stack to another
Stack& operator=(const Stack& rhs) {}
StackNode *top; // top of stack
};
Now I have question. This .h
file obviously reveals some implementation details. The constructor and the destructor are both implemented in the .h
file. In my understanding, those should be implemented in .cpp
file. Also, there is that struct StackNode
which is also implemented in the .h
file. Is that even possible to implement in the .cpp
file and only declare it in the header file? As a general rule, wouldn't it be better if those were in the .cpp
implementation file? What would be the best way to code this thing so that it follows C++ rules?
Header files are not fundamentally different from source files.
A header can, in principle, contain the same code constructs that a source file can. The only thing that, by convention, distinguishes a header from a source file is that a header is supposed to be #include
d by other files, which we usually do not do with source files (although we could, if we felt adventurous).
The important thing now is what happens if a file gets #include
d by more than one source file. Mind you, this is basically equivalent to copy-pasting the same code to multiple .cpp files. There are certain things that will likely get you into trouble in this case.
In particular, if you end up with two definitions for the same symbol in two different source files, your program is not well-formed (according to the one-definition rule) and the linker will probably refuse to link your program.
With distinct source files this usually not a problem, unless you accidentally reuse a name in different contexts. As soon as header files step into the picture (which are just copy-pasted code), things start to look different. You can still put a definition in a header file, but if that header file then gets pulled in by more than one source file, you have yourself a nice violation of the one-definition-rule.
Therefore, the convention is to only put stuff into header files that is safe to be duplicated across multiple source files. This includes declarations, inline-function definitions and templates.
The key realization here is probably that header files are a rather archaic tool for sharing code between source files. As such, they rely heavily on the user being smart enough not to mess things up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With