Anuncios

Bienvenidos sean a este post, hoy veremos una tecnica muy particular.

Anuncios

Las plantillas o tipos parametrizados son un medio para enseñarle al compilador como crear una lista de cualquier tipo en lugar de crear un conjunto de listas de tipos especificos. Cuando creamos un tipo especifico desde una plantilla se llama instanciacion y las clases individuales se llaman instancia de una plantilla. Veamos como establecemos una plantilla (template):

template <class nombre>
class nombre_clase
{
	... instrucciones de la clase ...
}
Anuncios

Antes de cada clase agregaremos siempre la opcion de template para asignarle un nombre a la misma. Luego definiremos la clase que utilizaremos como plantilla. Esta sera como cualquier otra clase. Con sus partes publicas y privadas, asi como metodos y propiedades, pero veremos como se aplica lo definido en el template. Para entenderlo pasemos a analizar el siguiente ejemplo:

#include <iostream>

const int tamanoPredet = 5;

class Animal
{
public:
        Animal(int peso): suPeso(peso) {}
        Animal(): suPeso(0) {}
        ~Animal() {}
        int GetPeso() const { return suPeso; }
        void mostrar() const { std::cout << suPeso; }
private:
        int suPeso;
};

template <class T>
class Arreglo
{
public:
        Arreglo(int tamano = tamanoPredet);
        Arreglo(const Arreglo & rhs);
        ~Arreglo() { delete [] pTipo; }
        Arreglo & operator= (const Arreglo &);
        T & operator[] (int pos) { return pTipo[ pos ]; }
        const T & operator[] (int pos) const { return pTipo[ pos ]; }
        int largo() const { return tamano; }
private:
        T * pTipo;
        int tamano;
};

template <class T>
Arreglo< T >::Arreglo(int tam): tamano(tam)
{
        pTipo = new T[ tam ];
        for(int i=0; i < tam; i++)
                pTipo[i] = 0;
}

template <class T>
Arreglo< T >::Arreglo(const Arreglo & rhs)
{
        tamano = rhs.largo();
        pTipo = new T[tamano];
        for(int i=0; i < tamano; i++)
                pTipo[i] = rhs[i];
}

template <class T>
Arreglo< T > & Arreglo< T >::operator=(const Arreglo & rhs)
{
        if (this == &rhs)
                return *this;
        delete [] pTipo;
        tamano = rhs.largo();
        pTipo = new T[ tamano ];
        for(int i=0; i < tamano; i++)
                pTipo[i] = rhs[i];
        return *this;
}

int main()
{
        Arreglo< int > numerico;
        Arreglo< Animal > zoo;
        Animal* pAnimal;
        for(int i = 0; i < numerico.largo(); i++)
        {
                numerico[i] = i * 2;
                pAnimal = new Animal(i * 3);
                zoo[i] = *pAnimal;
        }
        for(int i = 0; i < numerico.largo(); i++)
        {
                std::cout << "numerico[" << i << "]:\t ";
                std::cout << numerico[i] << "\t";
                std::cout << "zoo[" << i << "]:\t ";
                zoo[i].mostrar();
                std::cout  << std::endl;
        }
        return 0;
}
Anuncios

Primero definiremos una constante que usaremos para establecer un tamaño predeterminado para los arrays. Luego definiremos una clase llamada Animal. Tendra una propiedad solamente en privado. En la parte publica tenemos los constructores para iniciar el valor de suPeso y luego dos metodos mas. El primero es para recuperar el valor de suPeso y el otro para mostrarlo.

Anuncios
Anuncios

La siguiente clase sera nuestra plantilla. En este caso le asignamos el nombre de T y esta la usaremos para que trabaje como un array, por eso se llama arreglo. Primero tenemos dos prototipos de constructores, el primero sera para crear el array y sino le pasamos un valor inicial procede a usar la constante definida al inicio. El segundo en cambio usa a rhs, del cual hablamos en este post, y sera para asignar los valores recibidos en el array. El destructor elimina el puntero que crearemos en la parte privada. Lo siguiente es una sobrecarga del operador de asignacion, la cual definiremos en un momento. Despues tenemos la primera implementacion de la plantilla. Observen que tenemos un metodo para sobrecargar al operador de posicion de arrays pero no le pasamos un tipo sino que pasamos el nombre que asignamos a la plantilla o template. Esto es asi porque cuando le pasemos el tipo, ya veremos como, este sera para reemplazar a T. Despues recibe un valor que representara a la posicion del array y en base a este devolveremos el valor en esa posicion. El siguiente es exactamente lo mismo pero para cuando debamos usarlo en una constante.

Anuncios

Por ultimo, tenemos un metodo para obtener el tamaño del array creado. En la parte privada tenemos un puntero y una propiedad. El puntero sera del tipo que recibamos como plantilla y el siguiente es para establecer el tamaño del array.

Anuncios

Lo siguiente sera definir los prototipos de la clase de la plantilla. Primero ira nuevamente la linea de template para indicarle cual es el nombre de la plantilla. Este en teoria recibe un valor, informado o el predeterminado, y en base a este estableceremos al puntero con el tipo informado y le asignaremos el tamaño que reciba. Para luego pasar por todo el array y asignarle el valor de 0 para iniciarlo. Tambien debemos observar como pasamos a la plantilla en la clase antes del operador de relacion, para establecerlo.

Anuncios

El siguiente constructor es muy similar al anterior pero este recibe el tipo de dato rhs, los argumentos del lado derecho del operador de asignacion, y dentro iniciaremos a la propiedad y el puntero. En el caso de la propiedad recibe el valor devuelto por largo y en el puntero crearemos un objeto del tipo de la plantillaa y el tamaño sera establecido con el valor anterior. Luego tenemos un bucle donde asignaremos cada valor de rhs a cada posicion del puntero.

Anuncios

Luego tenemos al metodo que sobrecarga al operador de asignacion. Observen en todos los casos como pasamos la clase de Arreglo, siempre con el nombre de la plantilla, y este tambien utiliza a rhs. Primero verificamos si el contenido del puntero actual es igual al recibido procede a devolverlo y sale del metodo. De lo contrario, elimina al puntero. Establecemos nuevamente el valor de tamano mediante rhs y largo. Creamos un nuevo punterio del tipo recibido en la plantilla con el tamaño anteriormente establecido. Y mediante un bucle le asignaremos todos los valores de rhs a las posiciones del puntero, tal como hicimos en el constructor anterior. Para finalmente devolver este puntero.

Anuncios

En el main primero definimos dos objetos del tipo Arreglo. Uno sera de tipo int y el otro de tipo Animal, miren como los pasamos. Estos seran recibidos y asignados a la plantilla T. Despues tenemos un puntero del tipo Animal. El primer bucle sera para agregar elementos en los dos arrays, en el primero solo es un calculo, y en el segundo es mediante el constructor de Animal. En el segundo bucle recuperamos todos los valores cargados en cada array. Compilemos y veamos como trabaja:

$ ./plantilla
numerico[0]:     0      zoo[0]:  0
numerico[1]:     2      zoo[1]:  3
numerico[2]:     4      zoo[2]:  6
numerico[3]:     6      zoo[3]:  9
numerico[4]:     8      zoo[4]:  12
$
Anuncios

Como pueden ver, con una sola clase pudimos manejar dos tipos diferentes de datos. Con lo cual podemos decir que esta implementacion permite que la clase Arreglo pueda manejar cualquier tipo de dato sin necesidad de realizar sobrecargas de los metodos.

Anuncios

En resumen, hoy hemos visto templates, plantillas, que es, para que sirve, como se utiliza, y un ejemplo practico para verlo en accion. Espero les sea de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios
pp258

Donatión

It’s for site maintenance, thanks!

$1.50