1
Informática IISesión 12: Herencia (2) – herencia múltiple
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
CONTENIDOCONTENIDO
Herencia Multiple1
Ambigüedades Herencia Múltiple2
Herencia Virtual3
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
C++ permite crear clases derivadas que heredan los miembros de una o más clases antecesoras. Esta es una característica en la que C++ difiere de
otros lenguajes. Esta característica tiene pros y contras.
La herencia múltiple: Consiste en el ensamblando una nueva clase con los
elementos de varias clases-base.
Herencia MúltipleHerencia Múltiple
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Cuando se desea declarar una clase derivada de varias clases base se utiliza una lista de las bases directas separadas por comas:
class ClaseDerivada : tipoAcceso ClaseB1, tipoAcceso ClaseB2,… {
//La clase derivada posee información de las clases bases (atributos y métodos). Además, puedo agregar y modificar información.
};
Clase_Derivada hereda todos los miembros de las clases antecesoras ClaseBase1, ClaseBase2, … Usando herencia pública sólo puede utilizar los miembros que
derivan de recursos públicos y protegidos en las clases base.
Herencia MúltipleHerencia Múltiple
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
class ClaseA { protected: int valorA;
public: ClaseA() : valorA(10) {} int getValor() const { return valorA; }};
class ClaseB { private: int valorB;
public: ClaseB() : valorB(20) {} int LeerValor() const { return valorB; }};
#include<iostream>using namespace std;
class ClaseC : public ClaseA, public ClaseB {public: ClaseC() {
valorA++;valorB++;
} };
int main() { ClaseC CC;
// Que valores se imprimen? cout << CC.LeerValor() << endl; cout << CC.getValor() << endl; cout << CC.valorA << endl; cout << CC.valorB << endl;
return 0;}
Herencia MúltipleHerencia Múltiple
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Herencia MúltipleHerencia Múltipleclass ClaseA { protected: int valorA;
public: ClaseA() : valorA(10) {} ClaseA(int va) : valorA(va) {} int getValor() const { return valorA; }};
class ClaseB { protected: int valorB;
public: ClaseB() : valorB(20) {} ClaseB(int vb) : valorB(vb) {} int LeerValor() const { return valorB; }};
#include<iostream>using namespace std;
class ClaseC : public ClaseA, public ClaseB { ClaseC(int va, int vb): ClaseA(va), ClaseB(vb) { }};
int main() { ClaseC CC(13,26);
cout << CC.LeerValor() << endl; cout << CC.getValor() << endl; cout << CC.valorA << endl; cout << CC.valorB << endl;
return 0;}
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
CONTENIDOCONTENIDO
Herencia Multiple1
Ambigüedades Herencia Múltiple2
Herencia Virtual3
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
AmbigüedadesAmbigüedades
“La herencia múltiple es uno de los puntos peliagudos del lenguaje C++.
Hasta el extremo que algunos teóricos consideran que esta característica debe evitarse, ya que además de los problemas teóricos, presenta también una gran dificultad técnica para su implementación en los compiladores.
Por ejemplo, surge la cuestión:• Si dos clases A y B son clases base de una
subclase D y ambas tienen propiedades con el mismo nombre
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
¿Que debe resultar en la subclase D? ¿Miembros Duplicados?, o ¿un miembro que sean la agregación de las propiedades de A y B?.
Los creadores del C++ optaron por un diseño que despeja cualquier posible ambigüedad, aunque ciertamente deriva en una serie de reglas y condiciones bastante intrincadas”
AmbigüedadesAmbigüedades
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
La herencia múltiple puede originar situaciones de ambigüedad Cuando una clase derivada contiene versiones
duplicadas de clases base Cuando clases bases contienen miembros con el
mismo nombre.
El problema de la ambigüedad puede ser resuelto si: Se especifica a cual de las clases bases pertenece la
propiedad heredada. Se re-define el miembro en la clase derivada
AmbigüedadesAmbigüedades
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
AMBIGÜEDADES: SOLUCIÓN 1
AMBIGÜEDADES: SOLUCIÓN 1class ClaseA {
public: ClaseA() : valorA(10) {} int LeerValor() const { return valorA; } protected: int valorA;};
class ClaseB { public: ClaseB() : valorB(20) {} int LeerValor() const { return valorB; } protected: int valorB;};
#include<iostream>using namespace std;
class ClaseC : public ClaseA, public ClaseB {};int main() { ClaseC CC;
cout << CC.LeerValor() << endl; return 0;}#include<iostream>using namespace std;
class ClaseC : public ClaseA, public ClaseB {};int main() { ClaseC CC;
// Manera correcta de hacerlo cout << CC.ClaseA::LeerValor() << endl; cout << CC.ClaseB::LeerValor() << endl; return 0;}
// Produce error de compilación por ambigüedad
Método Derivado de
ClaseA??
Método derivado de ClaseB??
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Ambigüedades: solución 2Ambigüedades: solución 2class ClaseA { public: ClaseA() : valorA(10) {} int LeerValor() const { return valorA; } protected: int valorA;}; class ClaseB { public: ClaseB() : valorB(20) {} int LeerValor() const { return valorB; } protected: int valorB;};
#include<iostream>using namespace std;
class ClaseC : public ClaseA, public ClaseB{ int LeerValor() const { return valorA + valorB; } };int main() { ClaseC CC;
cout << CC.LeerValor() << endl; return 0;}
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
AmbigüedadesAmbigüedades
Una clase puede: Ser heredada por muchas clases.
Pero no puede: Ser heredada más de una vez por una misma clase. Razón??
Ejemploclass D:tipoDeAcceso B1,tipoDeAcceso B1,…
Aunque … Este fenómeno se puede presentar de manera indirecta.
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
AmbigüedadesAmbigüedades
class ClaseA { ... };class ClaseB : public ClaseA { ... };class ClaseC : public ClaseA { ... };class ClaseD : public ClaseB, public ClaseC { ... };
ClaseD
ClaseA
ClaseCClaseB
ClaseA
Duplicación indirecta de
la ClaseA
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Problemas de accesoProblemas de acceso
class B { public: int b; int b0;};
class D:public C1,public C2{ public: D(){ c = 10; C1::c = 110; C2::c = 120; b = 12; C1::b = 11; C2::b = 12; B::b = 10; C1::B::b = 10; b0 = 0; C1::b0 = 1; C2::b0 = 2; }};
class C1 :public B { public: int b; int c;};
class C2 :public B { public: int b; int c;};
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
CONTENIDOCONTENIDO
Herencia Multiple1
Ambigüedades Herencia Múltiple2
Herencia Virtual3
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Si las clases base contienen elementos comunes Estos se ven duplicados en los objetos de la subclase
(clase-derivada).
Para evitar estos problemas, existe una variante de la herencia: La herencia virtual: cada objeto de la clase derivada
no contiene todos los recursos (atributos y métodos) de las clases-base si estos están duplicados.
Se busca evitar los problemas asociados a la ambigüedad.
Herencia VirtualHerencia Virtual
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Como hacer herencia virtual? Se antepone la palabra ‘virtual’ al nombre de una clase-
base al momento de definir la herencia. Así se declara una clase-base virtual, que da lugar a un
mecanismo con el mismo nombre.
Sintaxis:class ClaseD : virtual public B1, ...
Herencia VirtualHerencia Virtual
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
class B { public: int b; int b0;};
class D:public C1,public C2{ public: D(){ c = 10; C1::c = 110; C2::c = 120; b = 12; C1::b = 11; C2::b = 12; B::b = 10; C1::B::b = 10; b0 = 0; C1::b0 = 1; C2::b0 = 2; }};
class C1 : virtual public B { public: int b; int c;};
class C2 : virtual public B { public: int b; int c;};
Problemas de accesoProblemas de acceso
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Problemas de accesoProblemas de acceso
class ClaseA { ... };class ClaseB : virtual public ClaseA { ... };class ClaseC : virtual public ClaseA { ... };class ClaseD : public ClaseB, public ClaseC { ... };
ClaseD
ClaseCClaseB
ClaseA
Herencia múltiple NO
ambigua
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
EJEMPLOEJEMPLOusing namespace std; class B { public: int var; B() { var = 0; } };class X : public B {}; class Y : public B {}; class Z : public X, public Y {};
int main () { Z z1; cout << "Valores iniciales:" << endl; cout << " z1.var (de X) = " << z1.X::var << endl; cout << " z1.var (de Y) = " << z1.Y::var << endl;
z1.X::var = 1; z1.Y::var = 2; cout << "Valores finales:" << endl; cout << " z1.var (de X) = " << z1.X::var << endl; cout << " z1.var (de Y) = " << z1.Y::var << endl;}
Valores iniciales: z1.var (de X) = 0 z1.var (de Y) = 0Valores finales: z1.var (de X) = 1 z1.var (de Y) = 2
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
EJEMPLOEJEMPLOusing namespace std; class B { public: int var; B() { var = 0; } };class X : virtual public B {}; class Y : virtual public B {}; class Z : public X, public Y {};
int main () { Z z1; cout << "Valores iniciales:" << endl; cout << " z1.var (de X) = " << z1.X::var << endl; cout << " z1.var (de Y) = " << z1.Y::var << endl;
z1.X::var = 8; z1.Y::var = 20; cout << "Valores finales:" << endl; cout << " z1.var (de X) = " << z1.X::var << endl; cout << " z1.var (de Y) = " << z1.Y::var << endl;}
Valores iniciales: z1.var (de X) = 0 z1.var (de Y) = 0Valores finales: z1.var (de X) = 20 z1.var (de Y) = 20
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
Herencia VirtualHerencia Virtual Cuando se crea una estructura que posea herencia
virtual, deberemos tener cuidado con los constructores.
El constructor de la ClaseA deberá ser invocado desde el constructor de la ClaseD, ya que ni la ClaseB ni la ClaseC lo harán automáticamente.
ClaseD
ClaseCClaseB
ClaseA
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
#include <iostream>#include <cstring>
class Persona { public: Persona(char *n) { strcpy(nombre, n); } const char * LeeNombre() const { return nombre; } protected: char nombre[30];};class Empleado : public Persona { public: Empleado(char *n, int s) : Persona(n), salario(s) {} int LeeSalario() const { return salario; } void ModificaSalario(int s) { salario = s; } protected: int salario;};
Otro Ejemplo: Ojo a la virtualidad(1)Otro Ejemplo: Ojo a la virtualidad(1)
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
class Estudiante : public Persona { public: Estudiante(char *n, float no) : Persona(n), nota(no) {} float LeeNota() const { return nota; } void ModificaNota(float _nota) { nota = _nota; } protected: float nota;};
class Becario : public Empleado, public Estudiante { public: Becario(char *n, int s, float _nota) : Empleado(n, s), Estudiante(n, _nota) {}};
int main() { Becario * Fulanito; Fulanito = new Becario("Tarcisio", 1000, 7); cout << Fulanito->Estudiante::LeeNombre() << "," << Fulanito->LeeSalario() << "," << Fulanito->LeeNota() << endl; return 0;}
Otro Ejemplo: Ojo a la virtualidad(1)Otro Ejemplo: Ojo a la virtualidad(1)
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
#include <iostream>#include <cstring>
class Persona { public: Persona(char *n) { strcpy(nombre, n); } const char *LeeNombre() const { return nombre; } protected: char nombre[30];};
class Empleado : virtual public Persona { public: Empleado(char *n, int s) : Persona(n), salario(s) {} int LeeSalario() const { return salario; } void ModificaSalario(int s) { salario = s; } protected: int salario;};
Otro Ejemplo: Ojo a la virtualidad(2)Otro Ejemplo: Ojo a la virtualidad(2)
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
class Estudiante : virtual public Persona { public: Estudiante(char *n, float no) : Persona(n), nota(no) {} float LeeNota() const { return nota; } void ModificaNota(float no) { nota = no; } protected: float nota;};
class Becario : public Empleado, public Estudiante { public: Becario(char *n, int s, float no) : Empleado(n, s), Estudiante(n, no), Persona(n) {}};
int main() { Becario * Fulanito; Fulanito = new Becario(“Tarcisio", 1000, 7); cout << Fulanito->LeeNombre() << "," << Fulanito->LeeSalario() << "," << Fulanito->LeeNota() << endl; return 0;}
Otro Ejemplo: Ojo a la virtualidad(2)Otro Ejemplo: Ojo a la virtualidad(2)
2009/1Circuitos Digitales III 2010/1Circuitos Digitales III 2010/1Circuitos Digitales IIICircuitos Digitales III 2010/1Informática II Universidad de Antioquia
BibliografíaBibliografía
man, ¡no dude en utilizarlo!! Como Programar en C++ - Deithel & Deithel Ed.
PRENTICE HALL Sams Teach Yourself C++ in One Hour a Day, J.
Liberty,S. Rao, B. Jones
http://newdata.box.sk/bx/c/
Informática II
Top Related