Cool C/C++

Programacion en C/C++

Home Tutoriales Programación C/C++ Plantillas en C++
Plantillas en C++ PDF Imprimir E-mail
Escrito por adrianvaca   
Domingo, 20 de Marzo de 2011 19:25

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 (< y >), cada parámetro formal que representa un tipo debe estar precedido por la palabra clave class, como en:

template <class T>
template <class Element Type>
template <class BorderType, class FillType


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 T>
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 <iostream.h> 
#include <conio.h>

template <class T>
T minimo (* Array, int num_elemen

   
T min= Array [0] ;

   for (
int i=1inum_elemeni++)
        if( Array[ 
] < min
            
min = Array [ ];

   return 
min
} ;

template <class T>
T maximo (* Array, int num_elemen
{
   
T max= Array [0];

   for (
int i=1inum_elemeni++)
        if( Array[ 
] > max
            
max = Array [ ];

   return 
max
};

void main(void)

   
int ArrayInt [3] = { 286}; 
   
float ArrayFloat [3] = { 12.18.75.6 }; 
   
int i;
   
   
cout<<"Arreglo de enteros: ";
   for (
i=0i<3i++) 
         
cout << ArrayInt] << " "

   
cout << endl << "Numero minimo: " << minimo (ArrayInt3) << endl
         
<<"Numero maximo: " << maximo (ArrayInt3) << endl << endl;

   
cout << "Arreglo de flotantes: ";
   for (
i=0i<3i++) 
        
cout << ArrayFloat] << " "
        
cout << endl <<"Numero minimo: " << minimo (ArrayFloat3) << endl
               
<<"Numero maximo: " << maximo (ArrayFloat3);

   
getch(); 


Segundo programa

En este programa se hace uso de plantillas, para elaborar una función que permita ordenar los elementos de un arreglo.
Esta función recibe tiene como parámetros, un puntero al tipo de elemento dado, y dos enteros que indican los índices del primero y último elemento.
Aquí se hace uso del algoritmo OrdenarShell para llevar a cabo la tarea. En la función principal se prueba esta plantilla con arreglos de enteros y flotantes.

#include <iostream.h>
#include <conio.h>

template <class T>
void Ordenar aint stint fn
{
   
int ik;
   
T item_a_ordenar;

   
;

   do 
   {
       
k1
    } while (
fn st 1) ;

   do 
   {
       
/= ;

       for (
ist+ki<=fni++) 
       { 
             
item_a_ordenar ] ; 
             
;

            while (
item_a_ordenar j-k]) 
            { 
               
j] =j-k] ; 
               
-=k;

               if(
st+k
                 break; 
            }

            
[j]=item_a_ordenar
        } 
   } while(
1); 
}

void main(void)

    
int Arraylnt[3] = { 23} ;
    
float ArrayFloat[3] = {25.03.045.2 } ;
    
int i ;

    
cout << "Enteros: " << endl
          
<< "Arreglo original: ";

    for (
i=0i<3i++) 
          
cout << Arraylnt] << " ";

    
Ordenar(Arraylnt02); 
    
cout << endl << "Luego de ordenar: ";

    for (
i=0i<3i++) 
          
cout << Arraylnt] << " ";


    
cout << endl << endl 
          
<< "Flotantes: " << endl 
          
<< "Arreglo original: "

    for (
i=0i<3i++) 
          
cout << ArrayFloat] << " ";

    
Ordenar(ArrayFloat02); 
    
cout << endl << "Luego de ordenar: ";

    for (
i=0i<3i++) 
          
cout << ArrayFloat] << " ";


    
getch() ; 


Tercer programa

En este programa se implementa, mediante el uso de plantillas la clase NuevaPila, que consiste en una Pila, en la que se pueden llevar a cabo las operaciones como insertar y eliminar datos de la misma, mostrar en pantalla los datos de la pila.

Esta es una pila estática, con un número predefinido de 10 elementos.
En al función principal, se usa una pila de enteros, flotantes y
caracteres para poder llevar a cabo una prueba de la plantilla creada.

#include <iostream.h>
#include <conio.h>

enum estado_pila OKLLENAVACIA };

template <class T
class 
NuevaPila 

   
int tamanyo
   
*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 <class T>
NuevaPila <T> :: NuevaPila (int tam
{
   
tamanyo=tam;
   
tabla= new [tamanyo] ;
   
cima=0;
   
estado=VACIA;
}
 
template <class T>
void NuevaPila <T> :: meter (T elemento

   if( 
estado!=LLENA
       
tabla [cima++]=elemento;
    else 
cout << "*** Pila llena ***";

    if(
cima>=tamanyo
       
estado=LLENA
    else 
       
estado=OK
}

template <class T>
T NuevaPila <T> :: 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 <class T>
void NuevaPila <T> :: visualizar () 

   for (
int i=cima-1>=0i--) 
        
cout << tabla] <<" "
}

template <class T
int NuevaPila <T> :: num_elementos () 
{
   return 
cima
}

void main() 
{
   
cout << "Probando pila de enteros";

   
NuevaPila <ints1 (5);
   
s1.meter(5);
   
s1.meter(10);
   
s1.meter(15);

   
cout << endl << "Numero de elementos: " << s1.num_elementos() << endl <<"Pila: ";  
   
s1.visualizar(); 

   
cout << endl << "Sacando elementos : " 
          
<< s1.sacar() <<" " << s1.sacar() << " " << s1.sacar() << endl
   
s1.sacar();

   
cout << endl << endl << "Probando pila de flotantes";
   
NuevaPila <floats2 (5);
   
s2.meter(7.5);
   
s2.meter(10.2);
   
s2.meter(15.3);

   
cout << endl << "Numero de elementos: " << s2.num_elementos() << endl
         
<<"Pila: "
   
s2.visualizar(); 
   
cout << endl << "Sacando elementos : " 
           
<< s2.sacar() << " " << s2.sacar() << " " << s2.sacar() << endl
   
s2.sacar ();

   
cout << endl << endl << "Probando pila de caracteres";
   
NuevaPila <chars3 (5);
   
s3.meter('m');
   
s3.meter('p');
   
s3.meter('s');

   
cout << endl << "Numero de elementos: " << s3.num_elementos() << endl <<"Pila: "
    
s3.visualizar(); 
    
cout << endl << "Sacando elementos : " 
          
<< s3.sacar () << " " << s3.sacar() << " " << s3.sacar() << endl
   
s3.sacar();


   
getch();


Cuarto ejemplo

Mediante el uso de plantillas cree una clase Cola, en la que se puedan llevar a cabo operaciones como: encolar, decolar e imprimir los datos miembro. Realice una función controladora para probar el uso de esta clase.
La clase NodoCola, tiene como amiga a la clase Cola.
Se presenta además una función para las opciones del usuario, y que se encarga de realizar las llamadas a las funciones de las clases. Esta
función es llamada desde main.
En la función main se ha usado como ejemplo una cola de enteros, aunque también se pudo haber usado otro tipo de datos como: char, double, y otros.

#include <iostream.h>
#include <conio.h>
#include <assert.h>

template <class TIPONODO>
class 
Cola;

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

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

      
friend class Cola <TIPONODO>;          // hace que Cola sea friend
};

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

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

// definicion enumeracion //
enum bool falsetrue };

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

template <class TIPONODO>
class 
Cola {
      
NodoCola <TIPONODO> * primero;          // puntero al primer nodo
      
NodoCola <TIPONODO> * 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 <TIPONODO> * getNuevoNodo (const TIPONODO &);
};

// constructor predeterminado
template <class TIPONODO>
Cola <TIPONODO> :: Cola (): primero(0), ultimo(0) { }

// destructor
template <class TIPONODO>
Cola <TIPONODO> :: ~Cola () {
     if( !
estaVacia() ) {         // ingresa si la cola no esta vacia
    
cout<<"Eliminando nodos ..." << endl;

    
NodoCola <TIPONODO> * actual primero, *temporal;

    while (
actual != 0) {     // borra los nodos restantes
           
temporal actual;
           
cout<< temporal->dato << endl;
           
actual actual->sig;
           
delete temporal;
    }
     }
     
cout << "Todos los nodos han sido eliminados" << endl << endl;
}

// inserta un nodo
template <class TIPONODO>
void Cola <TIPONODO> :: encolar (const TIPONODO valor) {
     
NodoCola <TIPONODO> * 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 <class TIPONODO>
bool Cola <TIPONODO> :: decolar (TIPONODO valor) {
     if( 
estaVacia() )                // la cola esta vacia
     
return false;                // eliminacion no satisfactoria

     
NodoCola <TIPONODO> *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 <class TIPONODO>
bool Cola <TIPONODO> :: estaVacia () const {
     if (
primero==0) return true;
     return 
false;
}

// imprime el contenido de la cola
template <class TIPONODO>
void Cola <TIPONODO> :: imprimir() const {
     if ( 
estaVacia() ) {
     
cout<<"La lista esta vacia" << endl << endl;
     return;
     }

     
NodoCola <TIPONODO> *actual primero;

     
cout<<"La cola es: ";

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

     
cout << endl << endl;
}

// funcion de utileria: devuelve un apuntador a un nodo recientemente asignado
template <class TIPONODO>
NodoCola <TIPONODO> * Cola <TIPONODO> :: getNuevoNodo (const TIPONODO valor) {
     
NodoCola <TIPONODO> * nuevo = new NodoCola <TIPONODO> (valor);
     
assert(nuevo!=0);
     return 
nuevo;
}

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

// funcion que prueba una cola
template <class T>
void probarCola Cola <T> & ObjetoCola) {

     
T valor;
     
int opcion;

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

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

              case 
2:
                 if(
ObjetoCola.decolar(valor))
                
cout<<"Dato " << valor <<" eliminado" << endl << endl;

                 else 
cout<<"No puede eliminar : la cola esta vacia" << endl << endl;

                 break;

              case 
3:
                 
ObjetoCola.imprimir();
                 break;
           }
           if(
opcion==4) break;
     }
}

// funcion principal
void main(){
     
clrscr();
     
Cola <intColaEnteros;
     
probarCola (ColaEnteros);



 
Otros artículos

Escribir un comentario


Código de seguridad
Refescar