Presentación 8

Anuncio
Templates
•
Templates (plantillas) son patrones utilizados para generar código,
que difiere de la forma normal de escribir código solamente en el
uso simbólico del nombre de un tipo.
•
Por ejemplo, se podría requeir de una función llamada max que
retorne el mayor de dos argumentos.
–
•
Utilizando técnicas convencionales, se debería escribir una función para
enteros, otra para dobles, y otra para cada tipo diferente para el que se
quiera realizar dicha comparación.
Los Templates permiten escribir una sola función y dejar que el
compilador genere código específico para cada tipo para el que se
requiera utilizar la función.
template <class T> T max(const T &t1, const T &t2)
{
return ((t2 > t1) ? t2 : t1);
}
El compilador crea una instancia de la función para algún tipo
específico al invocarla:
int y = 1;
int x = max(2,y);
•
POO
Este proceso trabaja adecuadamente si los tipos utilizados tienen
definidos las operaciones utilizadas de para la implementación de la
función (en este caso la comparación de magnitud).
1
Template Functions
Una función template es la declaración de una función, que utiliza un
tipo no especificado T como un parámetro formal, valor de retorno, o
variable local.
template<class T>
void Intercambiar(T &t1, T &t2)
{
T temp = t1;
t1 = t2;
t2 = temp;
}
Nota: Nada del procesamiento realizado en la función depende del
tipo real representado por el parámetro genérico T. Esto es un
requerimiento para que los templates tengan éxito.
Otro requirimiento es que le tipo genérico, T, posea las operaciones
utilziadas en la implementación de la función. En la función
Intercambiar, se requiere que T tenga un operador de asignación
operator=(...) y un constructor por copia, para crear un objeto
temporal de tipo T; caso contrario versiones generadas por el
compilador para construcción por copia y asignación deben ser
válidos, lo que está garantizado solo para los tipos nativos del
lenguaje.
Si no se cumplen las condiciones mencionadas, la compilación de la
función Intercambiar puede fallar, o, si el compilador puede
generar los el construtor y el operador mencionados, la operación de
la función puede ser incorrecta.
POO
2
///////////////////////////////////////////////////////////
////
intercambiar.cpp – demuestra templates para
//
////
funciones
//
///////////////////////////////////////////////////////////
#include <iostream.h>
template <class T> void Intercambiar(T &t1, T &t2)
{
T temp = t1;
t1 = t2;
t2 = temp;
}
void main()
{
int x = 1,
y = 2;
double u = 2.5, v = -3.3;
cout << “Prueba de funcion basada en templates \n\n";
cout << " Prueba con enteros\n";
cout << "
x = " << x << " and y = " << y << "\n";
cout << "
Intercambiar(x,y)\n";
Intercambiar(x,y);
cout << "
x = " << x << " and y = " << y << "\n\n";
cout
cout
cout
cout
<<
<<
<<
<<
"
"
"
"
Prueba con doubles\n";
u = " << u << " and v = " << v << "\n";
Intercambiar(u,v)\n"; Intercambiar(u,v);
u = " << u << " and v = " << v << "\n";
}
POO
3
Prueba de funcion basada en templates
Prueba con enteros
x = 1 and y = 2
Intercambiar(x,y)
x = 2 and y = 1
Prueba con doubles
u = 2.5 and v = -3.3
Intercambiar(u,v)
u = -3.3 and v = 2.5
POO
4
Clases Template
Clases basadas en Templates son clases que dependen de un tipo NO
específico para:
–
Un parámetro formal o valor de retorno para una función miembro.
–
Una variable local variable para una función miembro.
–
Un data miembro.
Una clase basada en templates podría derivarse de una clase que
dependa de algún tipo específico utilizando los siguientes criterios para
re-escribir la clase:
–
Reemplazar
class className { ... }
con
template<class T> class className { ... }
–
Para cada función miembro reemplace
TipoDeRetorno className::memName { ... }
con
template<class T>
TipoDeRetorno className<T>::memName { ... }
en donde TipoDeRetorno es ya sea T o un tipo específico
–
Reemplazar toda instancia de la clase
className obj;
con
className<type> obj;
–
Reemplazar todas las ocurrencias del tipo específico con el nombre del tipo
genérico T
A continiación se emplea una clase stack como un ejemplo para el uso
de los criterios espresados anteriormente. El resultado es una clase
genérica stack.
POO
5
Template Class Declaration
#ifndef TSTACK_H
#define TSTACK_H
// tstack.hpp - template stack class
//
modified from Effective C++, Scott
//Meyers by Jim Fawcett
#include <iostream>
#include <cstdlib>
template<class T>
class stack {
private:
struct listNode {
T data;
listNode *next;
// listNode constructor initializes node's data
// and sets next ponter to point to next node
listNode(const T& newdata, listNode *nextnode)
: data(newdata), next(nextnode) { }
};
listNode *top;
public:
stack();
// constructor
~stack();
// destructor
void push(const T& object);// put elements on
stack
T pop(void);
// remove elements
};
POO
6
Template Member Functions
in header file
POO
template<class T>
stack<T>::stack() : top(0) { }
template<class T>
stack<T>::~stack(void) {
while (top) {
listNode *next_to_die = top;
top = top->next;
delete next_to_die;
}
}
template<class T>
void stack<T>::push(const T &object) {
top = new listNode(object, top);
if(!top) {
std::cout << "\ndynamic memory exhausted\n";
exit(1);
}
}
template<class T>
T stack<T>::pop(void) {
static T safe;
if (!top) {
std::cout << "\nattempt to pop empty stack<T>\n";
return safe;
}
listNode *save = top;
top = top->next;
int data = save->data;
delete save;
return data;
}
#endif
7
Template Instantiation
// tstack.cpp - template stack class
//
modified from Effective C++, Scott
Meyers
using namespace std;
#include "tstack.h"
//----< test stub >-----------------------------------------//
template<class T>
void print_field(T t) {
cout.width(5);
cout << t;
}
void main() {
cout << "\nTesting Generic
stack<int> int_stack;
int x=1, y=2, z=3;
cout << "pushing " << x <<
int_stack.push(x);
cout << "pushing " << y <<
int_stack.push(y);
cout << "pushing " << z <<
int_stack.push(z);
POO
Stack Class\n\n";
" onto stack\n";
" onto stack\n";
" onto stack\n";
8
Template Instantiation
cout << "popping stack: ";
print_field(int_stack.pop());
cout << "\npopping stack: ";
print_field(int_stack.pop());
cout << "\npopping stack: ";
print_field(int_stack.pop());
cout << "\npopping stack: ";
int_stack.pop();
cout << endl;
stack<double> dbl_stack;
double a=1.5, b=2.5, c=3.5;
cout << "pushing " << a << " onto
stack\n";
dbl_stack.push(a);
cout << "pushing " << b << " onto
stack\n";
dbl_stack.push(b);
cout << "pushing " << c << " onto
POO stack\n";
dbl_stack.push(c);
9
Instantiation (continued)
Testing Generic Stack Class
pushing 1 onto stack
pushing 2 onto stack
pushing 3 onto stack
popping stack:
3
popping stack:
2
popping stack:
1
popping stack:
attempt to pop empty stack<T>
pushing 1.5 onto stack
pushing 2.5 onto stack
pushing 3.5 onto stack
popping stack:
3
popping stack:
2
popping stack:
1
popping stack:
attempt to pop empty stack<T>
POO
10
Descargar