Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
Ejemplo: Tipo Complejo Vamos a definir un tipo abstracto Complejo para describir números en el plano complejo representados de manera cartesiana (a+ bi donde a y b son respectivamente las magnitudes real e imaginaria) y de manera polar (re iα) donde α es un ángulo y r es el módulo. α a b r a+ bi = reαi 7 Complejo en C++ : parte pública 1 class Complejo { 2 public: 3 // observadores 4 float re() const; // parte real 5 float im() const; // parte imaginaria 6 7 // constructores 8 Complejo(float real, float imag); 9 static Complejo crear_polar(float mod, float ang); 10 11 // modificadores 12 void conjugar(); 13 14 // otras operaciones: 15 Complejo operator+(const Complejo & b) const; 16 float modulo() const; 17 float angulo() const; 18 /* ... sigue ... */ 9 Tipo abstracto – Especificación de operaciones Usaremos la sintaxis de contratos vista en la primera parte, con las siguientes modificaciones: I Los métodos de la clase T tienen un parámetro implícito T* this, que apunta al objeto sobre el cual se está operando. Un método const no permite modificar this. I Especificaremos Pre y Post de las operaciones en función de los observadores aplicados a this y/o a objetos del tipo especificado que se pasen como parámetro. I Observadores: conjunto minimal de métodos const que devuelven la información que caracteriza la instancia. Pueden tener Pre sobre los parámetros de entrada pero no tienen Post. I Constructores: la Pre sólo predica sobre los parámetros de entrada; la Post sobre el estado final del objeto en base a los observadores I Modificadores: modifican la instancia, potencialmente devolviendo además un resultado. En la Post se especifica cómo cambia la salida de los observadores, usando this y this0. 10 Ejemplo: Tipo Complejo – Espec. de operaciones Tipo Complejo Observadores: I float re() const // parte real I float im() const // parte imaginaria Constructores: I Complejo(float real,float imag) Post: *this.re() = real ∧ *this.im() = imag I static Complejo crear_polar(float mod, float ang) Post: res.re() = mod*cos(ang) ∧ res.im() = mod*sin(ang) Los métodos static son “de clase” y se ejecutan sin un objeto this sobre el cual operar. En este ejemplo, crear_polar sigue el patrón de constructor con nombre: una función que oficia de constructor. 11 Modificadores: I void conjugar() Pre: this = this0 Post: *this.re() = *this0.re()∧ *this.im() = −(*this0.im()) Otras operaciones: I Complejo operator+(const Complejo & b) const Post: res.re() = *this.re()+ b.re() ∧ res.im() = *this.im()+ b.im() I float modulo() const Post: res = √ *this.re()2 + *this.im()2 I float angulo() const Post: res = arctan2(*this.im(), *this.re()) 12 Ejemplo: Tipo Conjunto<T> Objetivo: abstraer el comportamiento de un conjunto de elementos de tipo T. Consideraciones: I La operación que caracteriza a un conjunto es el ∈ (pertence). I Es decir, un conjunto C queda definido completamente por qué elementos contiene o no. I Otras operaciones que tiene sentido modelar: ∪ (unión) y ∩ (intersección). I También es necesario poder agregar/quitar de a un elemento al conjunto. 13 Ejemplo: Tipo Conjunto<T> – Interfaz Observadores: I bool pertenece(const T & elem) const Constructores: I Conjunto<T>() Post: (∀t : T ) *this.pertenece(t) = false Modificadores: I void agregar(const T& e) Pre: this = this0 Post: (∀e′ : T ) *this.pertenece(e′) = true ⇐⇒ (*this0.pertenece(e′) = true ∨ e′ = e) I void quitar(const T& e) Pre: this = this0 Post: (∀e′ : T ) *this.pertenece(e′) = true ⇐⇒ (*this0.pertenece(e′) = true ∧ e′ 6= e) 14 Más modificadores: I void unir_con(const Conjunto<T> & c) Pre: this = this0 Post: (∀e : T ) *this.pertenece(e) = true ⇐⇒ (*this0.pertenece(e) = true ∨ c.pertenece(e) = true) I void intersecar_con(const Conjunto<T> & c) Pre: this = this0 Post: (∀e : T ) *this.pertenece(e) = true ⇐⇒ (*this0.pertenece(e) = true ∧ c.pertenece(e) = true) Otras operaciones: I int cardinal() const Post: res = ∑ e∈T β(*this.pertenece(e) = true) Nota: Esta sumatoria es sobre un dominio infinito 15 Conjunto<T> en C++: interfaz 1 template <typename T> 2 class Conjunto { 3 /*...*/ 4 } La palabra clave template I Si queremos implementar clases como vector<T> que tiene un parámetro de tipo T, necesitamos, en C++, usar templates para poder dejar a T a elección del usuario. I Un template define una “receta” para crear clases y funciones. Por ejemplo, vector es un template, y vector<int>, vector<float> y vector<vector<bool>> son tres posibles clases concretas que se fabrican a partir de ese template. I Instanciar un template es análogo a hacer copy-paste del template reemplazando T por el tipo elegido. 16 Conjunto<T> en C++: interfaz 1 template <typename T> 2 class Conjunto { 3 public: 4 // observadores 5 bool pertenece(const T& elem) const; 6 7 // modificadores 8 void unir_con(const Conjunto& c); 9 void intersecar_con(const Conjunto& c); 10 void agregar(const T& elem); 11 void quitar(const T& elem); 12 13 // otras operaciones 14 int cardinal() const; 15 /** ... sigue ... **/ 17
Compartir