Templates

Gracias a c++ podemos definir clases-plantilla: son clases PARAMETRIZABLES por lo general entidades abstractas que se pueden concretar en algo mas concreto. El ejemplo mas claro es de las estructuras de datos tradicionales: Pilas, Listas, Colas, etc.. Esas estructuras pueden contener distintos tipos de datos: enteros, strings, objetos,... Debemos reescribir la logica de cada estructura para cada tio de dato? NO! Podemos definir una clase plantilla para la Lista, la cola, la pila etc, y luego simplemente invocarlas especificando el tipo de dato. Asi de facil.

Figura: un caballero de la orden de los Templates

Veamos este horrible ejemplo de lista (atencion a la complicadilla sintaxis)

/**
* Lista.hpp
* Clase que define una estructura de datos lista Generica
*
* Pello Xabier Altadill Izura
*/

using namespace std;
#include <iostream>

// Asi es como declaramos una clase plantilla
// template <class nombre_generico> class NombreClase
template <class GENERICO> class Lista {

public:

	// Constructor
	Lista();

	// Constructor
	Lista(GENERICO elemento);

	// Constructor copia
	Lista(Lista const &);

	// Destructor
	~Lista();

	// agregar elemento
	void agregar(Lista *nodo);

	// se mueve hasta el siguiente dato
	Lista* siguiente();

	// comprueba si existe un elemento
	bool existe(GENERICO dato);

	// comprueba si existe un elemento
	GENERICO getDato() { return this->dato;}


private:
	
	// un elemento que apunta a otra lista, asi sucesivamente
	Lista *ladealao;

	// el dato es del tipo GENERICO
	GENERICO dato;

};

Y su implementacion

/**
* Lista.cpp
* Programa que implementa la clase de Lista generica
*
* Pello Xabier Altadill Izura
* Compilacion: g++ -c Lista.cpp
*
*/

#include "Lista.hpp"

// En la implementacion debemos detallar el tipo de dato,
// especificando todo el tema de plantilla, o sea que en lugar
// de poner Lista:: delante de cada funcion debemos poner TODO
// el churro siguiente
// template <class GENERICO> Lista<GENERICO>::nombreFuncion


// Constructor
template <class GENERICO> Lista<GENERICO>::Lista() {
	
	ladealao = 0;
	//dato = 0;
	cout << "Nueva lista creada." << endl;

}


// Constructor
template <class GENERICO> 
Lista<GENERICO>::Lista(GENERICO elemento) {

	ladealao = 0;
	dato = elemento;
	cout << "Nueva lista creada. Dato inicial: " << dato << endl;

}


// Constructor copia
template <class GENERICO> Lista<GENERICO>::Lista(Lista 
const & original) {

	ladealao = new Lista;
	ladealao = original.ladealao;
	dato = original.dato;

}


// Destructor
template <class GENERICO> Lista<GENERICO>::~Lista() {
}


// agregar elemento: AL LORO con donde se pone el retonno
template <class GENERICO> void 
Lista<GENERICO>::agregar(Lista *nodo) {
	
	nodo->ladealao = this;
	ladealao = 0; 

}


// se mueve hasta el siguiente dato
template <class GENERICO> Lista<GENERICO>* 
Lista<GENERICO>::siguiente() {
	
	return ladealao;

}


//Lista template <class GENERICO> Lista<GENERICO>::siguiente();
// comprueba si existe un elemento
template <class GENERICO> bool 
Lista<GENERICO>::existe(GENERICO dato) {
	
	return false;

}

Usando la lista Y ahora definimos una clase llamada Nombre. Crearemos una lista de nombres. Este es la definicion

/**
* Nombres.hpp
* Clase que define los nombres. No es mas que una 
cobaya para probar el template
*
* Pello Xabier Altadill Izura
*/

// Esta clase la usaremos en el template, no hay que definir nada en especial
class Nombre {

public:

	// Constructor
	Nombre():nombre("Jezabel") {}


	// Constructor
	Nombre(char *nombre) {

		this->nombre = nombre;

	}


	// Constructor copia
	Nombre(Nombre const &);

	// Destructor
	~Nombre(){}

	// agregar elemento
	char* getNombre() const { return this->nombre;}


private:
	
	// el dato
	char *nombre;

};

Y su implementacion y los ejemplos de uso de plantillas

/**
* Nombres.cpp
* Programa que implementa la clase nombres y utilza los templates
* para crear una lista de nombres.
*
* Pello Xabier Altadill Izura
* Compilando: g++ -o Nombre Lista.o Nombre.cpp
*/

#include "Nombre.hpp"
#include "Lista.hpp"


// Constructor copia
Nombre::Nombre(Nombre const & original) {
	
	nombre = new char;
	nombre = original.getNombre();

}


// Funcion principal para las pruebas
int main () {

	// Asi es como se implementan objetos con clases plantilla
	Lista<Nombre> listanombres;
	Lista<Nombre> *tmp, *final;
	
	Nombre test = Nombre("Prince");
	
	// podemos definir Listas de cualquier tipo basico
	Lista<int> listaenteros;

	// guardamos la posicion inicial; final es un puntero, le pasamos la direccion
	final = &listanombres;

	// vamos a crear unos cuantos NODOS y los a&ntilde;adimos
	tmp = new Lista<Nombre>;
	tmp->agregar(final);
	final = tmp;
	
	// otra mas...
	tmp = new Lista<Nombre>;
	tmp->agregar(final);
	final = tmp;

	// otra mas...
	tmp = new Lista<Nombre>;
	tmp->agregar(final);
	final = tmp;


	// y ahora recorremos la lista:
	tmp = &listanombres;
	
	while (tmp) {
	
		cout << tmp->getDato().getNombre() << endl;
		tmp = tmp->siguiente();

	}


	return 0;

}

Es un tema complejo pero util.