» » Curso De C++ - Parte 72

Curso De C++ - Parte 72

Curso De C++ - Parte 72

Curso De C++ - Parte 72

Funciones que usan plantillas como parámetros

Es posible crear funciones que admitan parámetros que sean una plantilla. Hay dos modos de pasar las plantillas: se puede pasar una instancia determinada de la plantilla o la plantilla genérica.
 
Pasar una instancia de una plantilla

Si declaramos y definimos una función que tome como parámetro una instancia concreta de una plantilla, esa función no estará disponible para el resto de las posibles instancias. Por ejemplo, si creamos una función para una tabla de enteros, esa función no podrá aplicarse a una tabla de caracteres:
// F_Tabla.cpp: ejemplo de función de plantilla para 
// Tabla para enteros:
// Mayo 2015 Tutoriales En Linea

#include <iostream>
#include "Tabla.h"
 
using namespace std;
 
const int nElementos = 5;

void Incrementa(Tabla<int> &t); // (1)

int main() {
   Tabla<int> TablaInt(nElementos);
   Tabla<char> TablaChar(nElementos);

   for(int i = 0; i < nElementos; i++) {
      TablaInt[i] = 0;
      TablaChar[i] = 0;
   }

   Incrementa(TablaInt);
   // Incrementa(TablaChar); // <-- Ilegal (2)

   for(int i = 0; i < nElementos; i++)
      cout << "TablaInt[" << i << "] = " 
           << TablaInt[i] << endl;

   return 0;
}

void Incrementa(Tabla<int> &t) { // (3)
   for(int i = 0; i < t.NElementos(); i++)
      t[i]++;
} 
En (1) vemos que el argumento que especificamos es Tabla<int>, es decir, un tipo específico de plantilla: una instancia de int. Esto hace que sea imposible aplicar esta función a otros tipos de instancia, como en (2) para el caso de char, si intentamos compilar sin comentar esta línea el compilador dará error. Finalmente, en (3) vemos cómo se implementa la función, y cómo se usa el parámetro como si se tratase de una clase corriente.

Pasar una plantilla genérica

Si declaramos y definimos una función que tome como parámetro una instancia cualquiera, tendremos que crear una función de plantilla. Para ello, como ya hemos visto, hay que añadir a la declaración de la función la parte template<class T>.
Veamos un ejemplo:
// F_Tabla2.cpp: ejemplo de función de plantilla 
// Tabla genérica:
// C con Clase: Marzo de 2002

#include <iostream>
#include <cstdio>
#include "Tabla.h"
#include "CCadena.h"
 
using namespace std;
 
const int nElementos = 5;

template<class T>
void Mostrar(Tabla<T> &t); // (1)

int main() {
   Tabla<int> TablaInt(nElementos);
   Tabla<Cadena> TablaCadena(nElementos);
   char cad[20];

   for(int i = 0; i < nElementos; i++) TablaInt[i] = i;
   for(int i = 0; i < nElementos; i++) {
      sprintf(cad, "Cad no.: %2d", i);
      TablaCadena[i] = cad;
   }

   Mostrar(TablaInt);    // (2)
   Mostrar(TablaCadena); // (3)

   return 0;
}

template<class T>
void Mostrar(Tabla<T> &t) { // (4)
   for(int i = 0; i < t.NElementos(); i++)
      cout << t[i] << endl;
} 
En (1) vemos la forma de declarar una plantilla de función que puede aplicarse a nuestra plantilla de clase Tabla. En este caso, la función sí puede aplicarse a cualquier tipo de instancia de la clase Tabla, como se ve en (2) y (3). Finalmente, en (4) vemos la definición de la plantilla de función.
 
Amigos de plantillas

Por supuesto, en el caso de las plantillas también podemos definir relaciones de amistad con otras funciones o clases. Podemos distinguir dos tipos de funciones o clases amigas de plantillas de clases:
 
Clase o función amiga de una plantilla

Tomemos el caso de la plantilla de función que vimos en el apartado anterior. La función que pusimos como ejemplo no necesitaba ser amiga de la plantilla porque no era necesario que accediera a miembros privados de la plantilla. Pero podemos escribirla de modo que acceda directamente a los miembros privados, y para que ese acceso sea posible, debemos declarar la función como amiga de la plantilla.

Modificación de la plantilla Tabla con la función Mostrar como amiga de la plantilla:
// Tabla.h: definición de la plantilla tabla:
// Mayo 2015 Tutoriales En Linea

#ifndef T_TABLA
#define T_TABLA

template <class T> class Tabla; // Declaración adelantada de Tabla
template <class T> void Mostrar(Tabla<T> &t); // Para poder declarar la función Mostrar

template <class T>
class Tabla {
  public:
   Tabla(int nElem);
   ~Tabla();
   T& operator[](int indice) { return pT[indice]; }
   const int NElementos() {return nElementos;}

   friend void Mostrar<>(Tabla<T>&); // (1) Y poder declararla como amiga de Tabla

  private:
   T *pT;
   int nElementos;
};

// Definición:
template <class T>
Tabla<T>::Tabla(int nElem) : nElementos(nElem) {
   pT = new T[nElementos];
}

template <class T>
Tabla<T>::~Tabla() {
   delete[] pT;
}
#endif
Programa de ejemplo:
// F_Tabla2.cpp: ejemplo de función amiga de 
// plantilla Tabla genérica:
// Mayo 2015 Tutoriales En Linea

#include <iostream>
#include <cstdio>
#include "Tabla.h"
#include "CCadena.h"
 
using namespace std;
 
const int nElementos = 5;
 
template<class T>
void Mostrar(Tabla<T> &t);  // (2)

int main() {
   Tabla<int> TablaInt(nElementos);
   Tabla<Cadena> TablaCadena(nElementos);
   char cad[20];

   for(int i = 0; i < nElementos; i++) TablaInt[i] = i;
   for(int i = 0; i < nElementos; i++) {
      sprintf(cad, "Cad no.: %2d", i);
      TablaCadena[i] = cad;
   }

   Mostrar(TablaInt);
   Mostrar(TablaCadena);

   return 0;
}

template<class T>
void Mostrar(Tabla<T> &t) { // (3)
   for(int i = 0; i < t.nElementos; i++)
      cout << t.pT[i] << endl;
} 
Nota (1): aunque esto no sea del todo estándar, algunos compiladores, (sin ir más lejos los que usa Dev-C++), requieren que se incluya <> a continuación del nombre de la función que declaramos como amiga, cuando esa función sea una plantilla de función. Si te fijas en (2) y (3) verás que eso no es necesario cuando se declara el prototipo o se define la plantilla de función. En otros compiladores puede que no sea necesario incluir <>, por ejemplo, en Borland C++ no lo es. 

Clase o función amiga de una instancia de una plantilla

Limitando aún más las relaciones de amistad, podemos declarar funciones amigas de una única instancia de la plantilla.

Dentro de la declaración de una plantilla podemos declarar una clase o función amiga de una determinada instancia de la plantilla, la relación de amistad no se establece para otras posibles instancias de la plantilla. Usando el mismo último ejemplo, pero sustituyendo la línea de la declaración de la clase que hace referencia a la función amiga:
template<class T>
class Tabla {
   ...
   friend void Mostrar<>(Tabla<int>&);
   ...
}; 
Esto hace que sólo se pueda aplicar la función Mostrar a las instancias <int> de la plantilla Tabla. Por supuesto, tanto el prototipo como la definición de la función "Mostrar" no cambian en nada, debemos seguir usando una plantilla de función idéntica que en el ejemplo anterior.

Comentarios 0

Deja un comentario

Información
Usuarios que están en este grupo no pueden dejar comentarios en la página