16.3.2. IntStack como plantilla

Aquí están el contenedor y el iterador de IntStack.cpp, implementados 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 de que una plantilla asume ciertas características de los objetos que está manejando. Por ejemplo, StackTemplate asume que hay algún tipo de operación de asignación para 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 especie de mecanismo de tipado débil en C++, que normalmente es un lenguaje fuertemente tipado. En vez de insistir en que un objeto sea de un tipo exacto para que sea aceptable, el tipado débil requiere únicamente que las funciones miembro a las que se quiere llamar estén disponibles 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[88].

Aquí está el ejemplo 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 de la plantilla 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 también un StackTemplate para manejar string. Esto se prueba leyendo las líneas del fichero de código fuente.



[88] Todos los métodos en Smalltalk y Python están débilmente tipados, y ése es el motivo por el que estos lenguajes no necesitan un mecanismo de plantillas. En efecto, se consiguen plantillas sin necesidad de plantillas.