First of all, comment that this issue has already been addressed in this other question:
I also recommend reading it since it has equally interesting answers.
Your error is a problem of concept.
In C ++ there is no problem in separating the implementation of the class from its declaration or interface. This is so because it is the task of the linker to sew the final program, then the consumers of your class just want to know the interface of the same to calculate the amount of memory that will consume on the stack , to know the signature of the functions, etc ...
However the templates are not classes to use. When you implement a template:
template<class T>
T func(T t)
{ return t * 2; }
The compiler does not generate any source code. When the compiler is a template is limited to point it in a list and continues its way ... is when you find uses of it when it starts to compile a template.
And why this strange behavior?
That a template, as such, does not have a valid code. In the previous example, what is T
exactly? How do we know that it can be multiplied by two? And how is that process exactly? Can you make copies of T
? We will not have answers until we know what specific type of data is T
.
If we now do the following:
int main()
{
std::cout << func(10);
}
We'll see that the program prints 20
, which is correct ... but if we do this other:
int main()
{
std::cout << func(10) << func("ABC");
}
We'll get a nice compilation error that says you do not know how to use the *
operator between a const char*
and a int
. The error has not come out until we have put an invalid use of the template, which shows that no code has been generated from the template until we try to use it.
Well, it also turns out that the C ++ compiler, in order to compile anything, a class, a function, a template ... you need to have your implementation available ... and here we have the origin of your problem. You have separated the declaration of the implementation and, at the time of using the template, the compiler only has the declaration, so it can not generate the corresponding code. Then the linker arrives and realizes that the functions you have to use are not available and the error that comes to you is generated.
To avoid problems, it is customary to leave the declaration and the implementation of the templates in the same file:
#ifndef nodo_h
#define nodo_h
#include <iostream>
template<class type>
class nodo
{
private:
type element;
nodo *next, *previous;
public:
void SetElement(type element);
void ShowElement();
type GetElement();
nodo* GetNext();
nodo* GetPrevious();
nodo();
~nodo();
};
template <class type>
nodo<type>::nodo()
{
next = NULL;
previous = NULL;
}
template <class type>
nodo<type>::~nodo()
{
}
template <class type>
void nodo<type>::SetElement(type element)
{
this->element = element;
}
template <class type>
void nodo<type>::ShowElement()
{
std::cout << element << endl;
}
template <class type>
type nodo<type>::GetElement()
{
return element;
}
template <class type>
nodo<type>* nodo<type>::GetNext()
{
return next;
}
template <class type>
nodo<type>* nodo<type>::GetPrevious()
{
return previous;
}
#endif
Note also that, in GetNext
and GetPrevious
you need to indicate the specialization of the return type:
template <class type>
nodo<type>* nodo<type>::GetNext()
// ^^^^^^
{
return next;
}
If you do not do it, the compiler will not know what the specialization of the template is and it will generate an error (error that does not come out right now because, as you can see, the functions are not being compiled)
And yes, this is necessary because a template can return anything and the compiler is not the one to decide for you.
Wait ... And why do not you need to update the header too? The code compiles and the statement is still bad :
template<class type>
class nodo
{
private:
type element;
nodo *next, *previous;
public:
void SetElement(type element);
void ShowElement();
type GetElement();
nodo* GetNext(); // <<--- ¿¿??
nodo* GetPrevious(); // <<--- ¿¿??
nodo();
~nodo();
};
Here there is no problem and it is because of how the language works. The uses of nodo
that the compiler finds in the declaration, if they do not have an explicit specialization, it is understood that they are specialized for the type type
. That is, the current statement is equivalent to the following:
template<class type>
class nodo
{
private:
type element;
nodo *next, *previous;
public:
void SetElement(type element);
void ShowElement();
type GetElement();
nodo<type>* GetNext();
nodo<type>* GetPrevious();
nodo<type>();
~nodo<type>();
};
And, by the way, try not to use using namespace
in the headers. For more information see this other question: