Cita:
Iniciado por vangodp Hombre... Para lo que sirve si lo sé
No pretendía enseñarte para qué sirven... solo mostrarte un par de trucos a usar con los templates ;)
Cita:
Iniciado por vangodp pero lo que has puesto ahí de ejemplo me va tardar un año entenderlo jajajaj.
Ya será menos.
La jerarquía de los nodos se compone de dos clases: NodoBase y Nodo<T>
NodoBase obliga a que las especializaciones de Nodo<T> implementen una serie de funciones (en el caso del ejemplo, sólo una). Este diseño te permite usar polimorfismo y usar todos los Nodo<T> (Nodo<int>, Nodo<float>, Nodo<string>...) como si fuesen un mismo tipo de objeto.
La gracia de este diseño es que podría almacenar elementos más complejos sin demasiado esfuerzo. En el siguiente ejemplo añado una especialización del template que almacena una estructura en vez de un tipo nativo:
Código C++:
Ver original#include <iostream>
#include <string>
class NodoBase
{
public:
NodoBase( )
: _siguiente( nullptr )
{ }
virtual ~NodoBase( )
{ }
void SetSiguiente( NodoBase* siguiente )
{ _siguiente = siguiente; }
NodoBase* Siguiente( ) const
{ return _siguiente; }
virtual void Pintar( std::ostream& out ) const = 0;
private:
NodoBase* _siguiente;
};
template< typename _TYPE_ >
class Nodo : public NodoBase
{
public:
Nodo( _TYPE_ valor )
: _valor( valor )
{ }
~Nodo( )
{ }
virtual void Pintar( std::ostream& out ) const
{ out << _valor; }
private:
_TYPE_ _valor;
};
struct ObjetoComplejo
{
std::string nombre;
int edad;
};
template< >
class Nodo< ObjetoComplejo > : public NodoBase
{
public:
Nodo( ObjetoComplejo valor )
: _valor( valor )
{ }
~Nodo( )
{ }
virtual void Pintar( std::ostream& out ) const
{ out << _valor.nombre << "(" << _valor.edad << ")"; }
private:
ObjetoComplejo _valor;
};
class Lista
{
public:
Lista( )
: _primero( nullptr )
{ }
virtual ~Lista( )
{
while( _primero )
{
NodoBase* siguiente = _primero->Siguiente( );
delete _primero;
_primero = siguiente;
}
}
template< class _TYPE_ >
void NuevoItem( _TYPE_ valor )
{
NodoBase* nuevoNodo = new Nodo< _TYPE_ >( valor );
if ( !_primero )
_primero = nuevoNodo;
else
{
NodoBase* nodo = _primero;
while( nodo->Siguiente( ) )
nodo = nodo->Siguiente( );
nodo->SetSiguiente( nuevoNodo );
}
}
void Pintar( std::ostream& out )
{
if ( !_primero )
{
out << "Lista vacía" << std::endl;
return;
}
_primero->Pintar( out );
NodoBase* nodo = _primero->Siguiente( );
while( nodo )
{
out << " -> ";
nodo->Pintar( out );
nodo = nodo->Siguiente( );
}
out << std::endl;
}
private:
NodoBase* _primero;
};
int main( )
{
Lista lista;
lista.NuevoItem( 1 );
lista.NuevoItem( 'c' );
lista.NuevoItem( "prueba" );
lista.NuevoItem( 4.56 );
ObjetoComplejo complejo;
complejo.nombre = "pepe";
complejo.edad = 31;
lista.NuevoItem( complejo );
lista.Pintar( std::cout );
}
Luego, lo que hace la clase "Lista" es almacenar una lista simple de elementos de tipo "NodoBase". La función que permite añadir nuevos elementos es un template, de tal forma que la especialización de la función es crear el nodo específico para el tipo T (por ejemplo, la especialización Pintar<int> es capaz de crear Nodo<int>). Esto quiere decir que, a la hora de la verdad, la función "Pintar" estará sobrecargada, existiendo una versión para cada tipo de nodo que deseemos añadir.
Una vez los nodos forman parte de la lista, el objeto "Lista" es capaz de interactuar con ellos haciendo uso de los métodos virtuales de "NodoBase". De esta forma puede, como he comentado antes, acceder a ciertas características de los nodos s