Aquí está el contenedor y el iterador de
IntStack.cpp
, implementado como una clase
contenedora genérica usando plantillas:
//: C16:StackTemplate.h // Simple stack template #ifndef STACKTEMPLATE_H #define STACKTEMPLATE_H #include "../require.h" template<class T> class StackTemplate { enum { ssize = 100 }; T stack[ssize]; int top; public: StackTemplate() : top(0) {} void push(const T& i) { require(top < ssize, "Too many push()es"); stack[top++] = i; } T pop() { require(top > 0, "Too many pop()s"); return stack[--top]; } int size() { return top; } }; #endif // STACKTEMPLATE_H ///:~
Listado 16.6. C16/StackTemplate.h
Hay que darse cuenta que esta plantilla asume ciertas
características de los objetos que está manejando. Por
ejemplo, StackTemplate
asume que hay
alguna clase de operación de asignación a T
dentro de la función
push()
. Se puede decir que una plantilla
«implica una interfaz» para los tipos que es
capaz de manejar.
Otra forma de decir esto es que las plantillas proporcionan una clase de mecanismo de tipado débil en C++, lo cual es típico en un lenguaje fuertemente tipado. En vez de insistir en que un objeto sea del mismo tipo para que sea aceptable, el tipado débil requiere únicamente que la función miembro a la que se quiere llamar esté disponible para un objeto en particular. Es decir, el código débilmente tipado puede ser aplicado a cualquier objeto que acepte esas llamadas a funciones miembro, lo que lo hace mucho más flexible[84].
Aquí tenemos el objeto revisado para comprobar la plantilla:
//: C16:StackTemplateTest.cpp // Test simple stack template //{L} fibonacci #include "fibonacci.h" #include "StackTemplate.h" #include <iostream> #include <fstream> #include <string> using namespace std; int main() { StackTemplate<int> is; for(int i = 0; i < 20; i++) is.push(fibonacci(i)); for(int k = 0; k < 20; k++) cout << is.pop() << endl; ifstream in("StackTemplateTest.cpp"); assure(in, "StackTemplateTest.cpp"); string line; StackTemplate<string> strings; while(getline(in, line)) strings.push(line); while(strings.size() > 0) cout << strings.pop() << endl; } ///:~
Listado 16.7. C16/StackTemplateTest.cpp
La única diferencia está en la creación de
is
. Dentro de la lista de argumentos del
template hay que especificar el tipo de objeto que la pila y
el iterador deberán manejar. Para demostrar la genericidad de
la plantilla, se crea un StackTemplate
para manejar string
. El ejemplo lee las líneas
del archivo con el código fuente.
[84] Todos los métodos en Smalltalk y Python están débilmente tipados, y ese es el motivo por lo que estos lenguajes no necesitan el mecanismo de los templates. En efecto, se consiguen plantillas sin templates.