Programación en C++ Herencia Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 1 Programación en C++ Introducción a la herencia • • • La herencia consiste en crear nuevas clases mediante la modificación de clases que ya existen: – Se heredan las variables miembros y las funciones miembro definidas. – Se pueden incorporar nuevas variables miembro o nuevas funciones miembro. – Se pueden redefinir o sobrecargar las variables y funciones miembro ya existentes. – Es un tipo de la clase ... Es un método alternativo a la definición de nuevas clases mediante la inclusión de clases ya definidas. – Es una clase independiente dentro de otra clase – Forma parte de la clase ... Clase base, clase hija (o clase derivada) – Las clases hijas añaden más información a la clase base. – Las clases base son más genéricas. Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 2 Programación en C++ Ejemplo de herencia • • • • Clase base de obstáculos (CObstaculo) que es una abstracción del concepto obstáculo. Clases derivadas: – CSegmento: obstáculos con forma de segmento. – CCirculo:obstáculo con forma de círculo. CObstaculo CSegmento CCirculo Aunque son obstáculos, la forma de procesarlos, es diferente Las clases hijas pueden acceder a la parte privada y protegida de la clase base Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 3 Programación en C++ Implantación del ejemplo de los obstáculos (I) class CObstaculo Ejemplo de clase base de obstáculos { private: double m_opacidad; protected: std::string m_sMensaje; public: ~CObstaculo(){}; // constructores CObstaculo(){ m_opacidad = 0; m_sMensaje = "Soy un obstaculo:";} CObstaculo(double opacidad) {m_opacidad = opacidad; m_sMensaje = "Soy un obstaculo:";}; void Identificacion(ostream& o) { o << m_sMensaje.c_str() << endl;}; }; Prof. Álvaro Sánchez Miralles Se identifica UPCO ICAI Departamento de Electrónica y Automática 4 Programación en C++ Implantación del ejemplo de los obstáculos (II) class CSegmento : public CObstaculo Características del segmento { private: CPunto m_p1, m_p2; // punto inicial y final del segmento double m_longitud, m_pendiente; // en grados -179 hasta 180 void Segmento(CPunto p1,CPunto p2); void Segmento(CPunto p1, double longitud, double pendiente); public: ~CSegmento(){}; Información del constructor que // constructores debe usar de la base CSegmento(){}; CSegmento(double opacidad):CObstaculo(opacidad){}; CSegmento(const CSegmento& r){*this=r;}; CSegmento(CPunto& p1, CPunto& p2){Segmento(p1,p2);}; CSegmento(CPunto& p1, double longitud, double pendiente) {Segmento(p1,longitud,pendiente);}; Acceso a la parte protegida de la base CSegmento& operator=(const CSegmento& r); void Identificacion(ostream& o) { m_sMensaje = "Soy un segmento:"; CObstaculo::Identificacion(o);}; }; Prof. Álvaro Sánchez Miralles que se de use la función de la base, UPCO ICAIDice Departamento Electrónica y Automática 5 no la propia del segmento Programación en C++ Implantación del ejemplo de los obstáculos (III) class CCirculo: public CObstaculo { private: CPunto m_p1; // centro del círculo double m_diametro; // diámetro del circulo void Circulo(CPunto p1,double diametro) {m_p1 = p1; m_diametro = diametro;}; public: ~CCirculo(){}; // constructores CCirculo(){}; CCirculo(double opacidad):CObstaculo(opacidad){}; CCirculo(const CCirculo& c){*this = c;}; CCirculo(CPunto p1,double diametro) { Circulo(p1,diametro);} CCirculo& operator=(const CCirculo& c); void Identificacion(ostream& o) { m_sMensaje = "Soy un círculo:"; CObstaculo::Identificacion(o);}; }; Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 6 Programación en C++ Prueba del ejemplo con obstáculos #include <list> La lista es: Soy un obstaculo: Soy un obstaculo: using namespace std; int main(int argc, char* argv[]) { list<CObstaculo> lo; list<CObstaculo>::iterator ilo; CPunto p(1,1); CSegmento r(p,2,0); CCirculo c(p,2); // rellena la lista con obstáculos lo.push_back(r); lo.push_back(c); // recorre la lista de obstáculos ilo=lo.begin(); cout << "La lista es: " << endl; for (int i = 0; i < lo.size() ; i++, ilo++) ilo->Identificacion (cout); ¿Pero no era un segmento y un círculo? return 0; } Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 7 Programación en C++ Funciones virtuales • • Es el principal mecanismo que tiene C++ para permitir polimorfismo – Si una clase hija sobrecarga una función virtual de su clase padre, entonces siempre que un objeto de la clase padre, que provenga de otro objeto de la clase hijo, vaya a usar esa función usará la función del hijo. – Es decir, el compilador garantiza una perfecta correspondencia entre objetos y las funciones virtuales que les corresponden. Una función miembro se declara virtual con el modificador virtual. Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 8 Programación en C++ Ejemplo de obstáculos con funciones virtuales class CObstaculo { ... virtual void Identificacion(ostream& o) { o << m_sMensaje.c_str() << endl;}; }; class CCirculo: public CObstaculo { ... void Identificacion(ostream& o) { m_sMensaje = "Soy un círculo:"; CObstaculo::Identificacion(o);}; }; class CCirculo: public CObstaculo { ... void Identificacion(ostream& o) { m_sMensaje = "Soy un círculo:"; CObstaculo::Identificacion(o);}; }; Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 9 Programación en C++ Prueba ejemplo de funciones virtuales #include <list> using namespace std; La lista es: Soy un segmento: Soy un círculo: int main(int argc, char* argv[]) { list<CObstaculo*> lo; El polimorfismo funciona sólo a list<CObstaculo*>::iterator ilo; nivel de punteros CPunto p(1,1); CSegmento r(p,2,0); CCirculo c(p,2); // rellena la lista con obstáculos lo.push_back(&r); lo.push_back(&c); Se introduce la dirección, ya que // recorre la lista de obstáculos la lista es de punteros a obstáculos ilo=lo.begin(); cout << "La lista es: " << endl; for (int i = 0; i < lo.size() ; i++, ilo++) (*ilo)->Identificacion (cout); return 0; } Prof. Álvaro Sánchez Miralles *ilo es el contenido del nodo de la lista; es decir, es un puntero a obstáculo UPCO ICAI Departamento de Electrónica y Automática 10 Programación en C++ Clases abstractas • Son clases que tienen al menos una función virtual sin código – Cada vez que se crea una clase derivada de esas clases abstractas hay que codificar las funciones que faltan – No se pueden declarar objetos de la clase base porque falta el código de algunas funciones. Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 11 Programación en C++ Ejemplo herencia completo (I) Objetivo: Sobrecargar el operador << para class CObstaculo admitir salida de datos de cualquier clase que { herede de obstáculos private: double m_opacidad; public: ~CObstaculo(){}; // constructores CObstaculo(){ m_opacidad = 0;} CObstaculo(double opacidad) {m_opacidad = opacidad;}; friend ostream& operator<<(ostream &o, CObstaculo* obs ); virtual void Imp(ostream& o)=0; Imp permite hacer polimorfismo en <<, }; ya que este operador es amigo ostream& operator<<(ostream &o, CObstaculo* obs) { obs->Imp(o); return o; } Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 12 Programación en C++ Ejemplo herencia completo (II) class CSegmento : public CObstaculo { ... public: ~CSegmento(){}; // constructores ... ver trasparencias anteriores CSegmento& operator=(const CSegmento& r); friend ostream& operator<<(ostream &o, CSegmento& r); void Imp(ostream& o){o<<*this;} Sobrecarga de Imp }; CSegmento& CSegmento::operator=(const CSegmento& r){ m_p1 = r.m_p1; m_p2 = r.m_p2; m_longitud = r.m_longitud; m_pendiente = r.m_pendiente; return(*this); } ostream& operator<<(ostream &o, CSegmento& r){ o << "Segmento: " << r.m_p1 << " " << r.m_p2 << endl; return o; } Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 13 Programación en C++ Ejemplo herencia completo (III) class CCirculo: public CObstaculo { ... public: ~CCirculo(){}; // constructores ... ver trasparencias anteriores CCirculo& operator=(const CCirculo& c); friend ostream& operator<<(ostream &o, CCirculo& r); void Imp(ostream& o){o<<*this;} }; ostream& operator<<(ostream &o, CCirculo& r){ o << "Circulo: " << r.m_p1 << " " << r.m_diametro << endl; return o; } CCirculo& CCirculo::operator=(const CCirculo& c){ m_diametro = c.m_diametro; m_p1 = c.m_p1; return(*this); } Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 14 Programación en C++ Ejemplo herencia completo (IV) class CPunto A continuación el resto de código { no relevante que falta private: double m_x; double m_y; public: double x(){return m_x;} double y(){return m_y;} CPunto(){Punto(0,0);} CPunto(double x, double y){Punto(x,y);} CPunto(const CPunto& p){m_x = p.m_x; m_y = p.m_y;} CPunto& operator=(const CPunto& p) {m_x = p.m_x; m_y = p.m_y; return(*this);} void Punto(double x, double y) {m_x = x; m_y=y;} CPunto& operator+=(CPunto& p) {m_x += p.m_x; m_y += p.m_y; return(*this);} CPunto& operator*=(double p){m_x *= p; m_y *= p; return(*this);} CPunto& operator/=(double p){m_x /= p; m_y /= p; return(*this);} CPunto& operator-=(CPunto& p) {m_x -= p.m_x; m_y -= p.m_y; return(*this);} friend ostream& operator<<(ostream &o, CPunto& p); }; Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 15 Programación en C++ Ejemplo herencia completo (V) ostream& operator<<(ostream &o, CPunto& p){ o << p.m_x << " " << p.m_y; return o; } void CSegmento::Segmento(CPunto p1, double longitud, double pendiente){ double x,y; m_longitud = longitud; m_pendiente = pendiente; x = p1.x() + longitud*cos(pendiente*PI/180); y = p1.y() + longitud*sin(-pendiente*PI/180); m_p1.Punto(p1.x(),p1.y()); m_p2.Punto(x,y); } void CSegmento::Segmento(CPunto p1, CPunto p2){ m_p1 = p1; m_p2 = p2; m_longitud = sqrt((p2.x()-p1.x())*(p2.x()-p1.x())+(p2.y()-p1.y())*(p2.y()p1.y())); if (p2.x() == p1.x()) if (p2.y() > p1.y()) m_pendiente = -90; else m_pendiente = 90; else { m_pendiente = atan((p1.y()-p2.y())/(p2.x()-p1.x()))*180/PI; if ((p1.x() > p2.x()) && (p1.y() > p2.y())) m_pendiente += 180; else if ((p1.x() > p2.x()) && (p1.y() < p2.y())) m_pendiente -= 180; } } Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 16 Programación en C++ Prueba herencia completo #include <list> using namespace std; int main(int argc, char* argv[]) { list<CObstaculo*> lo; list<CObstaculo*>::iterator ilo; CPunto p(1,1); CSegmento r(p,2,0); CCirculo c(p,2); La lista es: Segmento: 1 1 3 1 Circulo: 1 1 2 // rellena la lista con obstáculos lo.push_back(&r); lo.push_back(&c); // recorre la lista con obstáculos ilo=lo.begin(); cout << "La lista es: " << endl; for (int i = 0; i < lo.size() ; i++, ilo++) cout << *ilo; cout << endl; return 0; } Prof. Álvaro Sánchez Miralles UPCO ICAI Departamento de Electrónica y Automática 17