lunes, 15 de noviembre de 2010

Plantillas en C++

Las plantillas nos permiten especificar, con un solo segmento de código, un rango completo de funciones relacionadas (sobrecargadas), llamadas funciones de plantilla, o un rango completo de clases relacionadas, llamadas clases de plantilla.

Podríamos escribir una sola plantilla de función para una función de ordenamiento de arreglos y luego hacer que C++ generara automáticamente funciones de plantilla separadas que ordenaran un arreglo de int, un arreglo de float, un arreglo de string, etc.

Podríamos escribir una sola plantilla de clase de pila y luego hacer que C++ generara automáticamente clases de plantillas separadas, tales como una clase de pila de int, una clase de pila de float, una clase de pila de string, etc.

Hay que observar la diferencia entre las plantillas de función y las funciones de plantilla: las plantillas de función y las plantillas de clase son como plantillas con las cuales trazamos formas, y las funciones de plantilla y las clases de plantilla son como los trazos separados, que tienen la misma forma pero pueden trazarse en colores diferentes, por ejemplo.

Plantillas de función

Las funciones sobrecargadas se utilizan normalmente para realizar operaciones similares sobre diferentes tipos de datos. Si las operaciones son idénticas para cada tipo, esto puede realizarse en forma más compacta y conveniente mediante el uso de plantillas de función. Basándose en los tipos de argumento que se proporcionan en las llamadas a esa función, el compilador genera automáticamente funciones de código objeto separadas para manejar adecuadamente cada tipo de llamada. En C esta tarea se puede realizar mediante macros creadas con la directiva de preprocesador #define.

Sin embargo las macros presentan la posibilidad de serios efectos secundarios y no permiten que el compilador realice revisión de tipo. Las plantillas de función proporcionan una solución compacta similar a la de las macros, pero permiten una revisión de tipo completa. Todas las definiciones de plantillas de función comienzan con la palabra clave témplate, seguida de una lista de parámetros formales para dicha plantilla encerrados entre paréntesis angulares (<>), cada parámetro formal que representa un tipo debe estar precedido por la palabra clave class, como en:

template
template
template


Los parámetros formales de una definición de plantilla se utilizan (como sucedería con los argumentos de tipos integrados o de tipos definidos por el usuario) para especificar los tipos de argumentos de la función, para especificar el tipo de devolución de la función y para declarar variables en el interior de la función.

Para definir una plantillas de clase, se puede usar el siguiente formato:

template
class Nombre { . . .uso del parámetro T en funciones o datos miembro.. }


Primer programa

El siguiente programa hace uso de plantillas para determinar el mínimo y máximo valor de un arreglo de elementos dado.
La primera función recibe tiene como parámetros un puntero al tipo de elemento dado y el número de elementos y retorna el menor de los elementos que se encuentran en el arreglo.
La segunda función recibe los mismos parámetros y retorna el mayor de los elementos presentes en el arreglo.
Finalmente en la función main, se hace una prueba de estas funciones, con arreglos de enteros y flotantes.

#include
#include

template
T minimo (T * Array, int num_elemen)
{
T min= Array [0] ;

for (int i=1; i< min =" Array" t="">
T maximo (T * Array, int num_elemen)
{
T max= Array [0];

for (int i=1; i<> max)
max = Array [ i ];

return max;
};

void main(void)
{
int ArrayInt [3] = { 2, 8, 6};
float ArrayFloat [3] = { 12.1, 8.7, 5.6 };
int i;

cout<<"Arreglo de enteros: "; for (i=0; i<3; i="0;">
#include

template
void Ordenar ( T * a, int st, int fn)
{
int i, j , k;
T item_a_ordenar;

k = 1 ;

do
{
k= 3 * k + 1;
} while (k < i=" st+k;" item_a_ordenar =" a" j =" i"> 1);
}

void main(void)
{
int Arraylnt[3] = { 2, 3, 1 } ;
float ArrayFloat[3] = {25.0, 3.0, 45.2 } ;
int i ;

cout << "Enteros: " << i="0;" i="0;" i="0;" i="0;">
#include

enum estado_pila { OK, LLENA, VACIA };

template
class NuevaPila
{
int tamanyo;
T *tabla;
int cima;
estado_pila estado;

public:
NuevaPila(int =10);
~NuevaPila() { delete [] tabla; }
void meter (T);
T sacar ();
void visualizar ();
int num_elementos ();
int leer_tamanyo () { return tamanyo; }
}

template
NuevaPila :: NuevaPila (int tam)
{
tamanyo=tam;
tabla= new T [tamanyo] ;
cima=0;
estado=VACIA;
}

template
void NuevaPila :: meter (T elemento)
{
if( estado!=LLENA)
tabla [cima++]=elemento;
else cout << "*** Pila llena ***"; if(cima>=tamanyo)
estado=LLENA;
else
estado=OK;
}

template
T NuevaPila :: sacar ()
{
T elemento=0;

if(estado!=VACIA)
elemento=tabla[--cima];
else cout<<"*** Pila vac¡a ***"; if(cima<=0) estado=VACIA; else estado=OK; return elemento; } template
void NuevaPila :: visualizar ()
{
for (int i=cima-1; i >=0; i--)
cout << t="">
int NuevaPila :: num_elementos ()
{
return cima;
}

void main()
{
cout << "Probando pila de enteros"; NuevaPila s1 (5);
s1.meter(5);
s1.meter(10);
s1.meter(15);

cout <<> s2 (5);
s2.meter(7.5);
s2.meter(10.2);
s2.meter(15.3);

cout <<> s3 (5);
s3.meter('m');
s3.meter('p');
s3.meter('s');

cout <<>
#include
#include

template
class Cola;

///////////////////////////////////
// definicion clase NodoCola /////
//////////////////////////////////

template
class NodoCola {
TIPONODO dato; // dato
NodoCola * sig; // puntero siguiente nodo
public:
NodoCola (const TIPONODO &); // constructor
TIPONODO getDato() const; // devuelve dato del nodo

friend class Cola ; // hace que Cola sea friend
};

// constructor
template
NodoCola :: NodoCola (const TIPONODO & info)
: dato(info), sig (0) { }

// devuelve una copia del dato que esta en el nodo
template
TIPONODO NodoCola :: getDato() const {
return dato;
}

// definicion enumeracion //
enum bool { false, true };

//////////////////////////////////
// definicion clase Cola /////////
//////////////////////////////////

template
class Cola {
NodoCola * primero; // puntero al primer nodo
NodoCola * ultimo; // puntero al ultimo nodo
public:
Cola (); // constructor
~Cola(); // destructor
void encolar (const TIPONODO &); // permite insertar nodo
bool decolar (TIPONODO &); // permite eliminar nodo
bool estaVacia() const; // verifica si la cola esta vacia
void imprimir() const; // imprime datos de la cola

// funci¢n de utileria para asignar un nuevo nodo
NodoCola * getNuevoNodo (const TIPONODO &);
};

// constructor predeterminado
template
Cola :: Cola (): primero(0), ultimo(0) { }

// destructor
template
Cola :: ~Cola () {
if( !estaVacia() ) { // ingresa si la cola no esta vacia
cout<<"Eliminando nodos ..." <<> * actual = primero, *temporal;

while (actual != 0) { // borra los nodos restantes
temporal = actual;
cout<<>dato << actual =" actual-">sig;
delete temporal;
}
}
cout << "Todos los nodos han sido eliminados" << tiponodo="">
void Cola :: encolar (const TIPONODO & valor) {
NodoCola * nuevo = getNuevoNodo (valor);

if ( estaVacia() ) // si la cola esta vacia
primero=ultimo=nuevo;

else { // si la cola no esta vacia
ultimo->sig=nuevo;
ultimo=nuevo;
}
}

// elimina un nodo
template
bool Cola :: decolar (TIPONODO & valor) {
if( estaVacia() ) // la cola esta vacia
return false; // eliminacion no satisfactoria

NodoCola *temporal = primero;

if(primero==ultimo)
primero=ultimo=0;

else
primero=temporal->sig;

valor=temporal->dato; // dato que se esta eliminando
delete temporal;
return true; // eliminacion satisfactoria
}

// verifica si la cola esta vacia
template
bool Cola :: estaVacia () const {
if (primero==0) return true;
return false;
}

// imprime el contenido de la cola
template
void Cola :: imprimir() const {
if ( estaVacia() ) {
cout<<"La lista esta vacia" <<> *actual = primero;

cout<<"La cola es: "; while (actual!=0) { cout<<>dato <<" "; actual=actual->sig;
}

cout << tiponodo="">
NodoCola * Cola :: getNuevoNodo (const TIPONODO & valor) {
NodoCola * nuevo = new NodoCola (valor);
assert(nuevo!=0);
return nuevo;
}

/////////////////////////////////////////////////////////////////////////////

// funcion que prueba una cola
template
void probarCola ( Cola & ObjetoCola) {

T valor;
int opcion;

for (;;){
cout<<<"(1) Insertar, (2) Eliminar, (3) Imprimir, (4) Salir"<<<"Seleccion: "; cin>>opcion;

switch( opcion ){
case 1:
cout<<"Ingrese dato: "; cin>> valor;
ObjetoCola.encolar(valor);
break;

case 2:
if(ObjetoCola.decolar(valor))
cout<<"Dato " << opcion="="> ColaEnteros;
probarCola (ColaEnteros);

}


FUENTE: www.programacionenc.net


No hay comentarios:

Publicar un comentario