|
|
|
Universidad de Costa Rica
Escuela de Ciencias de la
Computación e Informática
|
|
El truco del Tdef.h
para la enseñanza de plantillas C++
Presentamos una técnica sencilla que facilita la
enseñanza de
plantillas para el
lenguaje C++.
|
We discuss a simple technique to facilitate teaching C++
templates.
|
int main() {
Stack_int S;
int d = -1;
S.Push(1); // 1
S.Push(2); // 1 2
S.Push(3); // 1 2 3
S.Push(4); // 1 2 3 4
S.Push(5); // 1 2 3 4 5
d = S.Pop(); // 1 2 3 4 [5]
d = S.Count(); // 4
|
S.Push(6); // 1 2 3 4 6
d = S.Count(); // 5
S.Push(7); // 1 2 3 4 6 7
d = S.Count(); // 6
d = S.Pop(); // 1 2 3 4 6 [7]
d = S.Count(); // 5
return 0;
} // main()
|
Figura 1
La
programación
genérica es una idea que tiene más de 20
años de antigüedad pero que siempre ha sido
difícil de explicar debido a la necesidad de dominar los
conceptos básicos sobre
abstracción de
algoritmos y
abstracción de
datos lo que fuerza a los profesores a esperar a un curso
avanzado para introducir este tema. Debido que en realidad las
plantillas son "polimorfismo de editor de texto"
[MDC-91],
es posible explicar plantillas pronto, de forma precisa y
sencilla, con base en los
"macro" del lenguaje C++. En la
Figura 1 está un sencillo
programa para introducir el concepto de
contenedor como un
objeto que almacena
otros objetos.
int main() {
Stack_int S;
// ...
} // main()
|
class Stack_int {
public:
Stack_int() { m_top = 0; return; }
void Push(int d) { m_vec[m_top] = d; m_top++; return; }
int Pop() { m_top--; return m_vec[m_top]; }
int Top() { return m_vec[m_top-1]; }
int Count() { return m_top; }
private:
enum { Capacity = 132 };
int m_top; // tope de la pila
int m_vec[Capacity]; // vector para la pila
}; // Stack_int
|
Figura 2: tStack2.cpp
Los
estudiantes
comprenden fácilmente que un vector se puede usar para
implementar
las
operaciones de la
pila. Por eso la implementación que está en la parte
de abajo de la
Figura 2 les resulta familiar.
int main() {
Stack_T S;
// ...
} // main()
|
typedef int T;
class Stack_T {
public:
Stack_T() { m_top = 0; return; }
void Push(T d) { m_vec[m_top] = d; m_top++; return; }
T Pop() { m_top--; return m_vec[m_top]; }
T Top() { return m_vec[m_top-1]; }
int Count() { return m_top; }
private:
enum { Capacity = 132 };
int m_top; // tope de la pila
T m_vec[Capacity]; // vector para la pila
}; // Stack_T
|
Figura 3: tStack3.cpp
En la
Figura 3 se muestra el resultado de
hacer unos pequeños cambios con el
editor de textos
para obtener la clase "Stack_T
" cuya funcionalidad es
similar a la de la clase "Stack_int
" de la
Figura 2.
Es sencillo para los alumnos entender las ventajas de contar con
una clase más general pues basta modificar una única
línea de código para obtener una
clase
genérica:
"typedef int T;
"
// Tdef.h
#ifndef Tdef_h
#define Tdef_h
typedef int T;
#endif // Tdef_h
|
// Tdef.h
#ifndef Tdef_h
#define Tdef_h
#define T int
#endif // Tdef_h
|
#ifndef Tdef_h
#include "Tdef.h"
#endif // Tdef_h
class Stack_T {
public:
Stack_T() { m_top = 0; return; }
void Push(T d) { m_vec[m_top] = d; m_top++; return; }
T Pop() { m_top--; return m_vec[m_top]; }
T Top() { return m_vec[m_top-1]; }
int Count() { return m_top; }
private:
enum { Capacity = 132 };
int m_top; // tope de la pila
T m_vec[Capacity]; // vector para la pila
}; // Stack_T
|
Figure 4: tStack4.cpp
El truco del
"Tdef.h
" consiste en
trasladar la línea en que se define el
tipo de dato
almacenado en la pila a un
archivo de
encabezado llamado
"Tdef.h
".
El programa principal es el mismo que se usó en la
Figura 2. En la parte de arriba de la
Figura 4 hay 2 versiones del archivo
"Tdef.h
" que sirve para
parametrizar la
pila. Al explicar por qué es necesario usar las directivas
de compilación condicional "#ifndef
" se puede
también explicar cómo funcionan las macros y el
preprocesador C++.
int main() {
Stack<int> S;
// ...
} // main()
|
template <class T>
class Stack {
public:
Stack() { m_top = 0; return; }
void Push(T d) { m_vec[m_top] = d; m_top++; return; }
T Pop() { m_top--; return m_vec[m_top]; }
T Top() { return m_vec[m_top-1]; }
int Count() { return m_top; }
private:
enum { Capacity = 132 };
int m_top; // tope de la pila
T m_vec[Capacity]; // vector para la pila
}; // Stack
|
Figura 5: tStackT.cpp
Después de haber definido la clase genérica es
relativamente sencillo transformarla en una clase con plantillas,
como la de la
Figura 5. Muchos alumnos escogen usar la
clase que usa
"Tdef.h
", sin
plantillas, porque al codificar un programa el compilador emite
errores con un significado más fácil de entender que
si usaran plantillas.
Los estudiantes lo prefieren a pesar de la limitación que
tiene el contenedor pues sólo permite un tipo de datos.
Los resultados de usar esta técnica didáctica son
muy buenos, pues toma un alrededor de 2 horas introducir los
conceptos de plantillas después de haber cubierto el
preprocesador C++ y sus "macros". Debido a que los estudiantes
comprenden cómo funciona el mecanismo de sustitución
textual para plantillas, pueden escribir y depurar sus programas
genéricos con un esfuerzo relativamente pequeño,
pues primero construyen la versión
"Tdef.h
" y luego la
"emplantillan" cuando ya está depurada.
El truco del "Tdef.h
" tiene varias ventajas
importantes:
Miguel Angel Prieto,
Manuel Enrique Bermúdez
y
Alejandro Di Mare
aportaron varias observaciones y sugerencias importantes para
mejorar este trabajo.
|
|
[AHU-84]
|
Aho, Alfred V.; Hopcroft, John E.; Ullman, Jefrrey D.:
Data Structures and Algorithms,
Addisson Wesley Publishing Co.,
1984.
|
[Low-2003]
|
Lowy, Juval:
An Introduction to C# Generics,
Microsoft MSDN Library;
August 2003.
http://msdn.microsoft.com/library/en-us/dnvs05/html/csharp_generics.asp
|
[MDC-91] |
Morrison, P. & Dearle, A. & Connor, R. C. H. & Brown, A. L.:
An Ad Hoc Approach to the Implementation of
Polymorphism,
ACM Transactions on Programming Languages and Systems,
Vol.13 No.3,
pp [342-371],
Julio 1991.
http://www.dcs.st-and.ac.uk/research/publications/download/MDC+91.pdf
|
[Str-98]
|
Stroustrup, Bjarne:
The C++ Programming Language, 3rd edition,
ISBN 0-201-88954-4;
Addison-Wesley, 1998.
http://www.research.att.com/~bs/papers.html
|
[-] |
Resumen
|
[-] |
Conclusión
|
[-] |
Agradecimientos
|
|
|
Bibliografía
|
|
Indice
|
|
Acerca del autor
|
|
Acerca de este documento
|
|
Principio
Indice
Final
|
Adolfo Di Mare:
Investigador
costarricense en la Escuela de
Ciencias de la Computación e Informática
[ECCI] de la Universidad
de Costa Rica
[UCR], en donde ostenta el
rango de Profesor Catedrático. Trabaja en las
tecnologías de Programación e Internet. Es Maestro
Tutor del
Stvdivm Generale de la
Universidad Autónoma de Centro América
[UACA], en donde ostenta el
rango de Catedrático. Obtuvo la Licenciatura en la
Universidad de Costa Rica, la Maestría en Ciencias en la
Universidad de California, Los Angeles
[UCLA], y el Doctorado
(Ph.D.)
en la Universidad Autónoma de Centro América.
|
Adolfo Di Mare:
Costarrican Researcher at the Escuela
de Ciencias de la Computación e Informática
[ECCI], Universidad de
Costa Rica
[UCR], where he is full
professor. Works on Internet and programming technologies. He is
Tutor at the
Stvdivm Generale in
the Universidad Autónoma de Centro América
[UACA], where he is
Cathedraticum. Obtained the Licenciatura at UCR, and the Master
of Science in Computer Science from the University of California,
Los Angeles
[UCLA], and the
Ph.D.
at the Universidad Autónoma de Centro América.
|
Adolfo Di Mare <adolfo@di-mare.com>
Copyright © 2004 Adolfo Di Mare
Derechos de autor reservados © 2004
Adolfo Di Mare <adolfo@di-mare.com>