Introducción a la Programación Orientada a...

46
SEMINARIO C++ Introducción a la Programación Orientada a Objetos Parte 3 v. 20101014 Depto. Lenguajes y Sistemas Informáticos - Universidad de Alicante Pedro J. Ponce de León

Transcript of Introducción a la Programación Orientada a...

SEMINARIO C++

Introducción a laProgramación Orientada a Objetos

Parte 3v. 20101014

Depto. Lenguajes y Sistemas Informáticos - Universidad de Alicante

Pedro J. Ponce de León

2

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Gestión de memoria dinámica5. Atributos y métodos de clase6. Implementación de relaciones entre objetos7. Pruebas unitarias

C++ÍNDICE

3

C++FUNCIONES AMIGAS

Función Amiga: Función NO miembro de una clase,que puede tener acceso a la parte privada de esaclase. Rompe el principio de “encapsulación”.

Una función se declara como amiga de una clasemediante la palabra reservada “friend”.

class MiClase { friend void unaFuncionAmiga(int, MiClase&);public: //...private: int datoPrivado;};

4

C++FUNCIONES AMIGAS

void unaFuncionAmiga(int x, MiClase& c) { c.datoPrivado = x; // ¡OK!}

…int main() { MiClase objeto; unaFuncionAmiga(10,objeto);}

Conceptualmente, las funciones amigas forman partede la interfaz de una clase (tanto como las funcionesmiembro).

PROHIBIDO SU USO EN POO: rompen el principio deencapsulación.

8

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Gestión de memoria dinámica5. Atributos y métodos de clase6. Implementación de relaciones entre objetos7. Pruebas unitarias

C++ÍNDICE

9

C++BIBLIOTECA ENTRADA/SALIDA

ifstream y ofstream son en realidad clases. La biblioteca iostream (#include <iostream>)

define otras clases (más generales) para los flujos deentrada y salida: istream : flujo de entrada de caracteres

istream cin;

ostream : flujo de salida de caracteresostream cout;ostream cerr;

Nota: Las operaciones de lectura y escritura sobre ‘streams’ que se presentan a continuación funcionan para cualquier objeto de tipo istream/ostream (no sólo cin y cout).

11

C++BIBLIOTECA ENTRADA/SALIDA

Operaciones de salida: Operador <<

cout << 17; Se pueden concatenar llamadas

cout << x << y; Algunas operaciones:

Indicar el carácter de relleno:cout.fill(‘*’); // por defecto, espacio en blanco

Especificar el número mínimo de caracteres para la próxima operaciónde salida:cout.width(4); // por defecto, cero

cout.fill(‘*’); cout.width(4); cout << 12 << “+” << 1; // imprime **12+1 y no **12***+***1

13

C++BIBLIOTECA ENTRADA/SALIDA

Operaciones de entrada Operador >>. Definido para los tipos básicos. Salta espacios en

blanco (espacio, tabulador o salto de línea) Entrada numérica:

Salta espacios y lee dígitos hasta encontrar un espacio en blanco o un carácter no numérico. Importante: si la operación encuentra un carácter no númerico, deja el flujo de entrada en estado deerror y no almacena nada en la variable; Cuando el formato de entrada no es conocido (por ejemplo, en entrada interactiva), al leer enteros oreales se debe comprobar tras cada lectura que la operación no ha producido error. Por tanto no esbuena idea concatenar lecturas como en el ejemplo de arriba.

int x; float y; cin >> x >> y;

14

C++BIBLIOTECA ENTRADA/SALIDA

Operaciones de entrada para carácter

char c; cin >> c; Salta espacios y guarda en ‘c’ el primer carácter no blanco.

c=cin.get(); // ó cin.get(c) get() devuelve el siguiente carácter en el flujo de entrada.

No salta espacios.

15

C++BIBLIOTECA ENTRADA/SALIDA

Operaciones de entrada para cadenasstring s; cin >> s;

Salta espacios. Almacena caracteres en ‘s’ hasta encontrar un espacio en blanco o elfinal del fichero.

Lectura de una línea completa: Con cadenas tipo C:

cin.getline(char* destino,int numcar,char delimitador=‘\n’); Lee como máximo numcar-1 caracteres hasta encontrar el carácter delimitador o el

final del fichero. No salta espacios.

Con string:getline(istream& is, string s); Lee una línea completa de la entrada y la almacena en ‘s’ (no almacena el salto de

línea final)

char cadena[100]; cin.getline(cadena, 100); // equiv. a cin.getline(cadena,100,’\n’);

16

C++BIBLIOTECA ENTRADA/SALIDA

Otras operaciones de entrada

cin.ignore() descarta el siguiente carácter en cin

cin.ignore(int ncar) descarta ‘ncar’ caracteres en cin

cin.ignore(int ncar, char delim) descarta ‘ncar’ caracteres como máximo hasta llegar al delimitador (que también se descarta)

Los métodos ignore() son útiles para limpiar el flujo deentrada tras un error de lectura.

17

C++BIBLIOTECA ENTRADA/SALIDA

Otras operaciones de entrada

cin.fail() : devuelve cierto si ha habido algún error al leer la entrada cin.eof() : devuelve cierto si se ha alcanzado el final del fichero (se ha

intentado leer cuando no había nada en el buffer de entrada) cin.clear() : recupera al stream del estado "fail".

Importante: cuando un flujo de entrada está en estado ‘fail’no se puede leer nada de él.

if (!cin) {

// o ‘if (cin.fail())’: si ha habido algún error...cin.clear();

cin.ignore(...);

// ...siguiente operación de lectura}

19

C++BIBLIOTECA ENTRADA/SALIDA: ejemplo

void Fecha::leer() { do{ cout<<"Introduce fecha (formato dd/mm/aaaa)” <<endl; if (!cin) { cin.clear(); cin.ignore(100,'\n'); } cin >> dia; cin.ignore(); cin >> mes; cin.ignore(); cin >> anyo; } while (!cin);}

Entrada de datos numéricos con formato

24

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Gestión de memoria dinámica5. Atributos y métodos de clase6. Implementación de relaciones entre objetos7. Pruebas unitarias

C++ÍNDICE

25

En C++ varias funciones pueden utilizar el mismo nombre(selector) en el mismo ámbito, distinguiéndose por el número ytipo de sus argumentos. Estas funciones se dice que estánsobrecargadas. Sobrecarga de funciones miembro (en el ámbito de la clase)

class Coordenada {

public: ...

Coordenada distancia(Coordenada &op2);

Coordenada distancia(float &op2);

};

En general, cualquier función se puede sobrecargar.

C++SOBRECARGA DE FUNCIONES

26

En C++ se pueden sobrecargar los operadores dellenguaje para utilizarlos con cualquier tipo de dato,incluso clases definidas por el usuario.

Los operadores son en realidad funciones cuyo nombre

está formado por la palabra reservada operatorseguida del operador a sobrecargar.int operator+(int,int);

float operator+(float,int);

C++SOBRECARGA DE OPERADORES

27

Las expresiones 1), 2) y 3) son equivalentes:Coordenada a, b(5,3), c(10,10);

1) a=b+c;

2) a.operator=(b.operator+(c));

3) operator=(a,operator+(b,c));

En 2) los métodos operator= y operator+ deben serfunciones miembro de la clase. El primer operando es unobjeto de la clase (el segundo puede no serlo).

En 3) los métodos no son miembros de la clase. Se debe respetar el significado original de los operadores

para no confundir al usuario.

C++SOBRECARGA DE OPERADORES

28

Sobrecarga del operador de asignación (=)

C++SOBRECARGA DE OPERADORES. Asignación

Fecha& operator=(const Fecha& f) { if (this!=&f)

// protección contra autoasignación

{ d=f.d; m=f.m; a=f.a; }

return *this;}

Es un ejemplo de sobrecarga de un operador binario que modifica al objeto(operando de la izquierda):

Se almacena el resultado de la operación en el propio objetoSe devuelve referencia al objeto (esto permite concatenar operadores)

Fecha a,b,c;a=b=c; // a.operator=(b.operator=(c));

38

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Atributos y métodos de clase5. Gestión de memoria dinámica6. Implementación de relaciones entre objetos7. Pruebas unitarias

C++ÍNDICE

39

Atributos y métodos de clase

También llamados estáticos. Se representan subrayados en UML. Los atributos de clase son comunes a todos los objetos de la clase. Sólo existe una copia en memoria compartida por todos los

objetos. Los métodos de clase sólo pueden acceder directamente a

atributos de clase

40

Atributos y métodos de clase

class Fecha { public:

static const int semanasPorAño = 52; static const int diasPorSemana = 7; static const int diasPorAnyo = 365; static string getFormato(); static boolean setFormato(string); private:

static string cadenaFormato;};

41

Atributos y métodos de clase:Definición y acceso

//Fecha.cc// Definición de un atributo de clase no constantestring Fecha::cadenaFormato = “DD/MM/AAAA”;

// Definición de metodo estáticostring Fecha::getFormato() { return cadenaFormato;}

// main.cc (Acceso)int main() { Fecha f; cout << Fecha::semanasPorAnyo << “ “ << f.diasPorSemana << endl; cout << Fecha::getFormato() << “ “ << f.getFormato() << endl;}

42

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Atributos y métodos de clase5. Gestión de memoria dinámica6. Implementación de relaciones entre objetos7. Pruebas unitarias

C++ÍNDICE

43

C++GESTIÓN DE MEMORIA DINÁMICA (recordatorio)

Operadores new y delete new

Dato *pDato = new Dato; Dato *pArray = new Dato [nElem] ; Comprobación error: if (pDato==NULL)... Ventaja frente a array convencional: permite decidir el número de

elementos en tiempo de ejecución. delete

delete pDato; pDato=NULL;

delete [] pArray; pArray=NULL;

IMPORTANTE: No olvidar los corchetes en delete si los hemos usado en elnew correspondiente

44

C++GESTIÓN DE MEMORIA DINÁMICA

Array de objetos Hay que guardar memoria para dos conceptos

El array en sí mismo Cada uno de los objetos que componen el array Con variables automáticas, C++ permite hacer ambas cosas en una

sola línea:Naipe arrayDeCartas[52];

//invoca a ctor. por defecto de Naipe para cadacomponente

Con memoria dinámica:Naipe *arrayDeCartas[52];arrayDeCartas = new *Naipe[52]; // Array de punteros

for (int i=0; i<52; i++) arrayDeCartas[i] = new Naipe(…);

// permite invocar a ctores. sobrecargados

49

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Atributos y métodos de clase5. Gestión de memoria dinámica6. Implementación de relaciones entre objetos

C++ÍNDICE

50

Implementación de relacionesAsociación/Agregación -> mediante punteros

class Asignatura {...};

class Persona

{

private:

string nombre;

string dni;

vector<Asignatura*> amatr;public:

Persona() : amatr() {} ~Persona() {

amatr.clear(); // no destruye los objetos Asignatura }

void setNombre(string n);

string getNombre();

bool anyadeAsig(Asig &a) {

… amatr.push_back(&a); … }};

Persona- string nombre- string dni

…+ bool anyadeAsig(Asignatura &a)

Asignatura- string nombre- string créditos

…+ bool asignaAlumno(Persona &p)

0..10 - amatr

52

Implementación de relacionesComposición

class A {

private:

B b;…};

A

1 - b

B

class A {

private:

static const int MAXB=10; vector<B*> b; public:

A() {for (int i=0; i<10; i++)

b.push_back(new B());…}

…};

A

10 - b

B

A

0..10 - b

B

A

0..* - b

B

Composición: Un objeto A tiene (contiene, esta formado por) objetos B

class A { private:

static const intMAXB=10;

vector<B*> b;…};

class A { private:

vector<B*> b;…};

53

Implementación de relacionesComposición

A

0..10 - b

B

A::A(): b() { … }

A::addB(B& unB) {

… if (b.size()<MAXB)

b.push_back(new B(unB));

…}

A::~A() {

for (int i=0; i<b.size(); i++)

{ delete b[i]; b[i]=NULL; }

b.clear();

…}

A::A(const A& otroA)

: b(otroA.b.size()) {

…// ‘deep copy’

for (int i=0; i<b.size(); i++)

b[i] = new B(*(otroA.b[i]));

…}

InicialmenteA no contiene

ningún B

El objeto detipo A tiene supropia copia decomponentes B

Los componentesB desaparecen

con A

class A { private:

static const int MAXB=10;

vector<B*> b;…};

54

Implementación de relacionesComposición

A

* - b

B

A::A(): b() { … }

A::addB(const B& unB) {

… b.push_back(new B(unB));

…}

A::~A() {

for (int i=0; i<b.size(); i++)

{ delete b[i]; b[i]=NULL; }

b.clear();

…}

A::A(const A& otroA) {

…// ‘deep’ copy’

for (int i=0; i<otroA.b.size(); i++)

b.push_back(new B(*(otroA.b[i])));

class A {

private: vector<B*> b;

…};

55

1. Funciones amigas2. Entrada / Salida3. Sobrecarga de funciones y operadores4. Atributos y métodos de clase5. Gestión de memoria dinámica6. Implementación de relaciones entre objetos7. Pruebas unitarias

C++ÍNDICE

56

• La interfaz de una clase debe ser probada de manera sistemática.

• Una prueba unitaria comprueba que un método determinado, anteuna llamada determinada, se comporta como se espera.

• Se realiza un caso de prueba unitaria para cada función no trivial o métodode forma que cada caso sea independiente del resto.

• Las pruebas se realizan mediante aserciones

C++PRUEBAS UNITARIAS

58

Herramientas de pruebaSon unas colecciones de clases con las que se puedendesarrollar casos de prueba fácilmente.

Para c++ existen multitud de herramientas:• CPPUnit.• Boost.Test.• CPPUnitLite.• NanoCPPUnit.• Unit++.• CxxTest <-- Usaremos ésta

C++PRUEBAS UNITARIAS

59

C++PRUEBAS UNITARIAS: CXXTEST

Herramienta especifica de C/C++. Se considera una de las herramientasmás sencillas y potentes en comparación con el resto.Es software libre (GNU Lesser Public License)

Sólo necesita un compilador de c++ ligeramente moderno y actualizado ysoporte para alguno de los dos lenguajes en los que se basa: Python oPerl.

60

C++PRUEBAS UNITARIAS: CXXTEST

Instalación

1. Obtener CXXTEST: http://cxxtest.sourceforge.net

2. Desempaquetar en un subdirectorio ‘test’(normalmente en el directorio de trabajo)

(para las prácticas de POO, CXXTEST vendrápreinstalado en los autocorrectores).

61

C++PRUEBAS UNITARIAS: CXXTEST

UsoLas pruebas se organizan en clases escritas en ficheros .h; Cadamétodo cuyo nombre comience por ‘test’ es ejecutado por cxxtest.

Por ejemplo:// MyTestSuite.h#include <cxxtest/TestSuite.h> class MyTestSuite : public CxxTest::TestSuite { public: void testAddition( void ) { TS_ASSERT( 1 + 1 > 1 ); TS_ASSERT_EQUALS( 2 * 2, 5 ); }};

62

C++PRUEBAS UNITARIAS: CXXTEST

Ejecución de las pruebas:

$ cxxtestgen.pl --error-printer -o runner.cpp MyTestSuite.h$ g++ -o runner runner.cpp$ ./runner

Resultado:

Running 2 tests. MyTestSuite.h:15: Expected (2 * 2 == 5), found (4 != 5) Failed 1 of 2 tests Success rate: 50%

63

C++PRUEBAS UNITARIAS: CXXTEST

TS_ASSERT

Es la prueba básica. Comprueba que una expresión escierta.

void testCalculadora(){ TS_ASSERT( suma( 0, 0 ) == 0 );}

Especificación de casos de prueba mediante aserciones

64

C++PRUEBAS UNITARIAS: CXXTEST

TS_ASSERT_EQUALS

Verifica la igualdad entre dos expresiones.Equivalente al operador == en TS_ASSERT.

void testResta(){ TS_ASSERT_EQUALS(resta(4,2),2);}

Especificación de casos de prueba mediante aserciones

65

C++PRUEBAS UNITARIAS: CXXTEST

TS_ASSERT_DELTA

Se usa para comparar si dos valores son iguales hasta delta.Básicamente se usa para números en coma flotante.

void testSqrt( void ){ TS_ASSERT_DELTA(sqrt(4.0), 2.0, 0.00001);}

Especificación de casos de prueba mediante aserciones

66

C++PRUEBAS UNITARIAS: CXXTEST

TS_ASSERT_DIFFERS

Es lo contrario a TS_ASSERT_EQUALS. Se usa paracomprobar que dos valores son distintos. Esequivalente a usar != en TS_ASSERT.

void testNumeros ( void ){ TS_ASSERT_DIFFERS(5,7);}

Especificación de casos de prueba mediante aserciones

67

C++PRUEBAS UNITARIAS: CXXTEST

TS_WARN

Muestra una lista de mensajes de cosas por hacerdel tipo “to do”.

void testToDoLista( void ){ TS_WARN( "TODO: Escribir todos los test!");

Especificación de casos de prueba mediante aserciones

68

C++PRUEBAS UNITARIAS: CXXTEST

TS_FAIL

Muestra un fallo incondicional.

void testFallo(){ TS_FAIL( "No se puede testear." );}

Especificación de casos de prueba mediante aserciones

69

C++PRUEBAS UNITARIAS: CXXTEST

Dada una clase a evaluar, basta incluir su .h en el fichero de pruebas.Por ej., dada la clase Coordenada de la práctica 0:

#ifndef PUNTO_TESTSUITE_H_#define PUNTO_TESTSUITE_H_

#include <cxxtest/TestSuite.h>#include "../include/Punto.h"

class PuntoTestSuite : public CxxTest::TestSuite { Punto* c00; Punto* c11;

public: void setUp() { // Código que se ejecuta antes de cada prueba c00 = new Punto; c11 = new Punto; c11->setX(1.0); c11->setY(1.0); }

void tearDown() { // Código que se ejecuta después de cada prueba delete c00; c00=NULL; delete c11; c11=NULL; } ...

70

C++PRUEBAS UNITARIAS: CXXTEST

// (Continuación)

void testFormaCanonica() { // Prueba unitaria: método cuyo nombre empieza por ‘test’ TS_ASSERT_EQUALS(c11->getX(), 1); TS_ASSERT_EQUALS(c11->getY(), 1);

// Test constructor de copia const Punto c(*c11);

TS_ASSERT_EQUALS(c.getX(),1.0); TS_ASSERT_EQUALS(c.getY(),1.0);

// Test operator= Punto c7; c7.setX(2); c7.setY(3);

c7=c7; TS_ASSERT_EQUALS(c7.getX(),2.0); TS_ASSERT_EQUALS(c7.getY(),3.0);

c7=*c11; TS_ASSERT_EQUALS(c7.getX(),1.0); TS_ASSERT_EQUALS(c7.getY(),1.0); }

};

SEMINARIO C++

Introducción a laProgramación Orientada a Objetos

FIN parte III