16.3.2. IntStack como plantilla

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.