Plantillas

Anuncio
Programación en C++
Plantillas: un mecanismo de
polimorfismo
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 1
Programación en C++
Polimorfismo a través de programación genérica
•
•
•
•
Las plantillas permiten programar un clase o una función
de forma genérica: es decir que valga para diferentes tipos
de datos.
Ejemplo: la clase vector definida para enteros, tiene el
mismo código para doubles.
El tipo genérico utilizado en la plantilla debe soportar todos
las operaciones que se realizan en dicha plantilla:
– En la plantilla de vectores genéricos no se admite las operaciones
de sumar o multiplicación escalar porque los elementos pueden no
se numéricos (modelos de coche, ventanas, etc)
Se puede sobrecargar las funciones miembro de las
plantillas para casos especiales:
– Cuando se multiplican vectores numéricos se aplica la definición de
producto escalar
– Cuando se multiplican vectores no numéricos se da un error.
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 2
Programación en C++
Plantilla para la clase de vectores
template <class tipo> class TVec {
tipo es el tipo genérico. Cuando
private:
se crea un objeto de dicha clase
int m_nEle;
hay que concretar el tipo.
tipo *m_p;
Tipo genérico
Puede haber más de un tipo genérico.
public:
TVec(int nEleP=0);
TVec(const TVec<tipo>& P);
~TVec();
TVec& operator=(const TVec<tipo>& P);
tipo& operator[](int n);
tipo& operator[](int n) const;
friend ostream& operator<<(ostream &o,TVec<tipo>& v);
friend istream& operator>>(istream &o,TVec<tipo>& v);
private:
void Ini(int nEleP, tipo *pP);
void Borra();
TVec<tipo> es en general el tipo
#ifdef DEBUGVECTOR
de la clase mientras no haya que
void DebugCrea();
concretar el tipo
#endif
};
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 3
Programación en C++
Implantación de la plantilla de vectores (I)
#ifndef vector_h
#define vector_h
vec.h
#define DEBUGVECTOR
#include <iostream.h>
#include <assert.h>
template <class tipo> class TVec {
private:
int m_nEle;
tipo *m_p;
public:
TVec(int nEleP=0);
TVec(const TVec<tipo>& P);
~TVec();
TVec& operator=(const TVec<tipo>& P);
tipo& operator[](int n);
tipo& operator[](int n) const;
friend ostream& operator<<(ostream &o,TVec<tipo>& v);
friend istream& operator>>(istream &o,TVec<tipo>& v);
private:
// Resto en transparencia anterior
};
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 4
Programación en C++
Implantación de la plantilla de vectores (II)
vec.h
template <class tipo> TVec<tipo>::
TVec(int nEleP){
#ifdef DEBUGVECTOR
DebugCrea();
#endif
Ini(nEleP,0);
}
Se ha modificado Ini respecto de la
versión con int: no hay valor
por defecto. Si se hubiera incluido
supone crear un objeto del tipo
correspondiente, inicializado con
0. Para ser más eficiente se ha
quitado. Hay que inicializar los
elementos uno a uno, o tener
una función miembro de inicialización.
template <class tipo> TVec<tipo>::
TVec(const TVec<tipo>& o) {
#ifdef DEBUGVECTOR
DebugCrea();
#endif
Ini(o.m_nEle,o.m_p);
}
#ifdef DEBUGVECTOR
template <class tipo> void TVec<tipo>::
DebugCrea(){
cout<<"Creado objeto TVec "<<this<<endl;
}
#endif
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 5
Programación en C++
Implantación de la plantilla de vectores (III)
template <class tipo> void TVec<tipo>::
Ini(int nEleP, tipo *pP){
m_nEle=nEleP;
if (m_nEle<=0) {
// Vector nulo
m_nEle=0;
m_p=0;
return;
}
m_p=new tipo[m_nEle];
assert(m_p!=0);
if (pP!=0) {
// Inicializar con otro
for (int i=0;i<m_nEle;i++)
m_p[i]=pP[i];
return;
}
}
template <class tipo> TVec<tipo>::
~TVec(){
#ifdef DEBUGVECTOR
cout<<"Destruido objeto TVec "<<this<<endl;
#endif
Borra();
}
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
vec.h
El código de las plantillas
no es código final porque
no se sabe el tipo. Sólo
cuando se instancia la clase
con un tipo concreto el
compilador genera el
código final. Por esta razón
los compiladores no suelen
admitir el código de las
plantillas en los ficheros
*.cpp. Hay que colocarlos
en los *.h en los *.hpp (y se
incluyen en el *.h).
UPCO ICAI Departamento de Electrónica y Automática 6
Programación en C++
Implantación de la plantilla de vectores (IV)
template <class tipo> tipo& TVec<tipo>::
operator[](int n)
{
assert((n>=0)&&(n<m_nEle));
return m_p[n];
}
template <class tipo> tipo& TVec<tipo>::
operator[](int n) const
{
assert((n>=0)&&(n<m_nEle));
return m_p[n];
}
vec.h
Las funciones constantes
permiten asegurar que esa
función no va a cambiar el
contenido del objeto.
template <class tipo> TVec<tipo>& TVec<tipo>::
operator=(const TVec<tipo>& o){
if (this!=&o) {
Borra();
Ini(o.m_nEle,o.m_p);
}
return *this;
}
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 7
Programación en C++
Implantación de la plantilla de vectores (V)
template <class tipo>
istream& operator>>(istream &o,TVec<tipo>& v)
{
v.Borra();
o>>v.m_nEle;
v.Ini(v.m_nEle,0,0);
for(int i=0;i<v.m_nEle;i++) {
o>>v[i];
}
return o;
}
template <class tipo>
ostream& operator<<(ostream &o,TVec<tipo>& v)
{
o<<v.m_nEle<<" ";
for (int i=0;i<v.m_nEle;i++) {
o<<v[i]<<" ";
}
o<<endl;
return o;
}
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
vec.h
También se pueden construir
plantillas de funciones. Este
caso son las funciones
amigas del vector
encargadas de escribir y leer
UPCO ICAI Departamento de Electrónica y Automática 8
Programación en C++
Prueba de la plantilla de vectores
#include <iostream.h>
#include "vector.h"
main() {
TVec<int> vi1(2),vi2(3);
vi1[0]=-2;
vi1[1]=-30;
vi2[0]=-4;
vi2[1]=8;
vi2[2]=104;
cout<<"vi1: "<<vi1;
cout<<"v12: "<<vi2;
TVec<double> vd(3);
vd[0]=1.2;
vd[1]=2.3;
vd[2]=3.4;
cout<<"vd: "<<vi2;
TVec< TVec<int> > vvi(2);
vvi[0]=vi1;
vvi[1]=vi2;
cout<<vvi;
cin>>vvi;
cout<<vvi;
}
Creado objeto TVec 0x0012ff84
Creado objeto TVec 0x0012ff7c
vi1: 2 -2 -30
v12: 3 -4 8 104
Creado objeto TVec 0x0012ff74
vd: 3 1.2 2.3 3.4
Creado objeto TVec 0x0012ff6c
Creado objeto TVec 0x00883214
Creado objeto TVec 0x0088321c
2 2 -2 -30
3 -4 8 104
Destruido objeto TVec 0x0088321c
Destruido objeto TVec 0x00883214
2
Creado objeto TVec 0x00883214
Creado objeto TVec 0x0088321c
3 -1 -2 -3
5 0 1 234
2 3 -1 -2 -3
5 01234
Destruido objeto TVec 0x0012ff6c
Destruido objeto TVec 0x0088321c
Destruido objeto TVec 0x00883214
Destruido objeto TVec 0x0012ff74
Destruido objeto TVec 0x0012ff7c
Destruido objeto TVec 0x0012ff84
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
Vector de
vectores o de
lo que quiera
con una sola
línea de código
UPCO ICAI Departamento de Electrónica y Automática 9
Programación en C++
Resumen sobre plantillas
•
•
•
•
Mediante el uso de tipos genéricos un solo código sirve
para diferentes clases.
Cada clase concreta debe implantar todas las operaciones
que pide la clase o función plantilla.
Puntos que se deben chequear que no haya problemas
(especialmente si hay manejo de memoria dinámica):
– Constructor sin parámetros.
– Constructor de copia
– Asignación desde otro elemento del mismo tipo
Al igual que en la sobrecarga de operadores, se debe
vigilar la eficiencia del código.
Prof. José A. Rodríguez Mondéjar
Prof. Álvaro Sánchez Miralles
UPCO ICAI Departamento de Electrónica y Automática 10
Descargar