PDF de programación - Seminario de C++ - Sesión 3

Imágen de pdf Seminario de C++ - Sesión 3

Seminario de C++ - Sesión 3gráfica de visualizaciones

Publicado el 30 de Agosto del 2017
629 visualizaciones desde el 30 de Agosto del 2017
212,2 KB
12 paginas
Creado hace 19a (28/10/2004)
Algoritmos y Estructuras de Datos

Ingeniería en Informática, Curso 2º, Año 2004/2005

SEMINARIO DE C++

Sesión 3



Contenidos:

1. Funciones y clases genéricas
2. Excepciones
3. Asertos
4. El puntero this
5. Redefinición de operadores
Ejemplo



Algoritmos y Estructuras de Datos, 2004/2005
Seminario de C++ – Sesión 3

2/12

1. Funciones y clases genéricas



• Genericidad (parametrización de tipo): el significado de una función o de un
tipos de datos está definido en base a unos parámetros de tipo que pueden variar.
o Ejemplo: funciones genéricas. En lugar de: OrdenaInt(int array[]),
OrdenaCharP(char *array[]), OrdenaFloat(float array[]), ...,
tenemos Ordena<T>(T array[]).
o Ejemplo: clases genéricas. El lugar de las clases PilaInt, PilaChar,

PilaFloat, ..., tenemos una clase genérica Pila<T>.

• En C++, las funciones y clases genéricas se definen mediante sentencias

template (plantilla). La sintaxis es:

template < parámetros genéricos > función o clase genérica


- parámetros genéricos: Lista con uno o varios tipos genéricos (clases). Por

ejemplo: template <class T>..., template <class A, class B>...

- función o clase genérica: Declaración normal de una función o una clase,

pudiendo usar los tipos de la lista de parámetros genéricos.

• Funciones genéricas.

o Definición.
template < parámetros genéricos >
tipoDevuelto nombreFunción ( parámetros de la función )
{
cuerpo de la función
}



o Utilización. Llamar directamente a la función. El compilador, según los tipos

de los parámetros de entrada, instanciará la versión adecuada.

• Ejemplo. Función genérica ordena(T array[], int tam), que ordena un

array de elementos de cualquier tipo T.
#include <string> // Contiene la clase string, alternativa
// a los (char *) de C
#include <iostream>
using namespace std;

template <class T>
void ordena (T array[], int tam)
{
for (int i= 0; i<tam-1; i++)
for (int j= i+1; j<tam; j++)
if (array[j]<array[i]) {
T tmp= array[i];
array[i]= array[j];
array[j]= tmp;
}
}

//Pregunta: ¿qué pasaría si instanciamos T a (char *)?

Algoritmos y Estructuras de Datos, 2004/2005
Seminario de C++ – Sesión 3

3/12

template <class T>
void escribe (T array[], int tam)
{
for (int i= 0; i<tam; i++)
cout << array[i] << (i<tam-1? ", ": "\n");
}

#define numElems(ARRAY) sizeof(ARRAY)/sizeof(*ARRAY)

main ()
{
int a1[]= {65, 23, 12, 87};
ordena (a1, numElems(a1));
escribe (a1, numElems(a1));

string a2[]= {"hola", "esto", "es", "una", "prueba"};
ordena (a2, numElems(a2));
escribe (a2, numElems(a2));
}



• Clases genéricas.

o Definición de la clase.

template < parámetros genéricos >
class nombreClase
{
definición de miembros de la clase
};

o Implementación de los métodos. Para cada método de la clase tenemos:

template < parámetros genéricos >
tipoDevuelto nombreclase<par>::nombreFunción ( parámetros )
{
cuerpo de la función
}

o Utilización. La clase genérica se debe instanciar a un tipo concreto antes de

usarla. Instanciación: nombreclase<parámetros>.

• Ejemplo. Clase genérica pila<T>, de las pilas de cualquier tipo T.


#include <iostream>
#define MAXIMO 100
using namespace std;

template <class T> // Declaración de la clase
class pila
{
private:
int ultimo;
T datos[MAXIMO];
public:
pila () {ultimo= 0;} // Constructor
void push (T v);
void pop ();
T tope();
};

Algoritmos y Estructuras de Datos, 2004/2005
Seminario de C++ – Sesión 3

4/12


// Implementación de los métodos
template <class T>
void pila<T>::push (T v)
{
if (ultimo<MAXIMO)
datos[ultimo++]= v;
}

template <class T>
void pila<T>::pop ()
{
if (ultimo>0)
ultimo--;
}

template <class T>
T pila<T>::tope ()
{
return datos[ultimo-1];
}



// Programa principal
// Ejemplo de uso de la clase genérica
main ()
{
pila<int> p1; // p1 es una pila de enteros
p1.push(4); p1.push(9);
p1.pop();
cout << p1.tope() << '\n';

pila<char *> p2; // p2 es una pila de cadenas
p2.push("Ultimo"); p2.push("en"); p2.push("entrar");
p2.push("primero"); p2.push("en"); p2.push("salir");
for (int i= 0; i<6; i++, p2.pop())
cout << p2.tope() << '\n';

pila<float> *p3; // p3 es una pila de float que
p3= new pila<float>; // se crea dinámicamente
p3->push(1.3); p3->push(2.19); p3->push(3.14);
cout << p3->tope() << '\n';
delete p3;
}



• Probar:

1. Probar pilas de otros tipos: pila<char>, pila<pila<char> >, etc.
2. Implementar una operación igual, que compare dos pilas y devuelva true si

son iguales.

3. Probar la función igual.



• Existe una "pequeña pega" relacionada con las clases genéricas y la compilación

separada: el compilador sólo genera código cuando se instancia la clase genérica.

Problema: si separamos la definición de una clase genérica en fichero de
cabecera (pila.hpp) y de implementación (pila.cpp), la compilación (c++ -c
pila.cpp) no genera código objeto. Si otro módulo usa la case genérica (#include
"pila.hpp"), el compilador dirá que no encuentra la implementación de la clase.
la definición como
implementación de la clase deben ir en el mismo fichero, el hpp.

las clases genéricas,

Solución: para

tanto

la

Algoritmos y Estructuras de Datos, 2004/2005
Seminario de C++ – Sesión 3


2. Excepciones

5/12


• ¿Qué hacer si se produce un error irreversible dentro de un procedimiento? Por
ejemplo, hacer una división por cero, aplicar tope() sobre una pila vacía,
imposibilidad de reservar más memoria o de leer un fichero, etc.
1. Mostrar un mensaje de error por pantalla, o por la salida de error estándar:

cerr << "Error: la pila está vacía";

2. Devolver al procedimiento que hizo la llamada un valor especial que

signifique "se ha producido un error".

3. Interrumpir la ejecución del programa: exit(1)
4. No hacer nada y continuar con la ejecución del programa como mejor se

pueda.

5. Provocar o lanzar una excepción.


• Significado de las excepciones:



1. El procedimiento que lanza la excepción (lo llamamos A), interrumpe su

2. El procedimiento que ha llamado al A (lo llamamos B), debe tener un código

ejecución en ese punto.

para manejar excepciones.

3. Si el procedimiento B no maneja la excepción, la excepción pasa al que ha
llamado al B, y así sucesivamente hasta que alguien trate la excepción
(propagación de la excepción).

4. Si la excepción se propaga hasta el main() y este no maneja la excepción,

se interrumpe la ejecución del programa y se muestra un mensaje de error.


• Conceptualmente, una excepción es un objeto.

class ErrorPilaVacia {};
class DivisionPorCero {};
• Provocar una excepción. Sentencia: throw nombreClase();

double divide (int a, int b)
{
if (b==0)
throw DivisionPorCero();
return double(a)/double(b);
}

• Manejar una excepción. Bloque:
try {
sentencias1
}
catch (nombreClase) {
sentencias2
}

1. Ejecutar las sentencias de sentencias1 normalmente.
2. Si se produce una excepción del tipo nombreClase, ejecutar sentencias2.

Estas sentencias contienen el código de manejo de excepciones.



Algoritmos y Estructuras de Datos, 2004/2005
Seminario de C++ – Sesión 3

6/12



try {
double d1, d2, d3;
d1= divide(3, 4);
d2= divide(5, 0);
d3= divide(1, 2);
}
catch (DivisionPorCero) {
cerr << "División por cero\n";
};

• Manejar excepciones de cualquier tipo:

try {
sentencias1
}
catch (...) {
sentencias2
}

• Ejemplo.
#include <iostream>

class DivisionPorCero {};

double divide (int a, int b)
{
if (b==0)
throw DivisionPorCero();
return double(a)/double(b);
}

main()
{
try {
cout << divide(3, 4) << '\n';
cout << divide(5, 0) << '\n';
cout << divide(1, 2) << '\n';
}
catch (DivisionPorCero) {
cerr << "División por cero\n";
}
cout << "Acaba\n";
}



• Probar:

1. Ejecutar la división por cero fuera del bloque try ... catch ...
2. Cambiar catch (DivisionPorCero) por catch (...)
3. Ejecutar una sentencia throw dentro del main()



Algoritmos y Estructuras de Datos, 2004/2005
Seminario de C++ – Sesión 3

7/12



3. Asertos

• Asertos: verificar una condición. Si se cumple, seguir normalmente. Si no, se
muestra la línea de código donde falló el programa y se interrumpe la ejecución.
assert ( condición booleana );

• La función assert() está definida en la librería <assert.h>

• Los asertos se pueden utilizar para incluir precondiciones y postcondiciones.

funcion (parametros)
{
assert (precondición);
...
// Cuerpo de la función
...
assert (postcondición);
}

• Ejemplo. En el ejemplo de la página anterior sustituir la implementación de

divide() por la siguiente. No olvidar el #include <assert.h>
double divide (int a, int b)
{
assert(b!=0);
return double(a)/double(b);
}


• Si se define la macro NDEBUG, se desactiva la comprobación de todos los

asertos definidos. Probar en el ejemplo anterior.


• Ojo: Los asertos provocan la interrupción del programa.
• Otra posibilidad: comprobación de precondición y postcondición generando

excepciones. Definirse uno mismo las funciones...
class FalloPrecondicion {};
class FalloPostcondicion {};

void precondicion (bool condicion)
{
#ifndef NDEBUG
if (!condicion)
throw FalloPrecondicion();
#endif
}

void postcon
  • Links de descarga
http://lwp-l.com/pdf6669

Comentarios de: Seminario de C++ - Sesión 3 (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad