Está en la página 1de 112

TEMA 3 HERENCIA

Cristina Cachero, Pedro J. Ponce de Len


versin 3 (3 sesiones)

Depto. Lenguajes y Sistemas Informticos

Tema 3. HERENCIA Objetivos


!

Entender el mecanismo de abstraccin de la herencia. Distinguir entre los diferentes tipos de herencia Saber implementar jerarquas de herencia en C++ Saber discernir entre jerarquas de herencia seguras (bien definidas) e inseguras. Reutilizacin de cdigo: Ser capaz de decidir cundo usar herencia y cundo optar por composicin.

Herencia Del tema anterior


Persistente Entre objetos
"

No persist.

Asociacin Todo-Parte
" "

C1

C2

Uso (depend) C1 C2

"

Agregacin Composicin

Entre clases

"

Generalizacin

vehiculo areo

avion

helicoptero

HERENCIA Motivacin
Florista cobrar() darRecibo() Panadero cobrar() darRecibo() Vendedor coches

....

cobrar() darRecibo()

Asociamos ese comportamiento a una categora general (generalizacin)

CLASE DERIVADA (C++) CLASE HIJA SUBCLASE

Dependiente cobrar() darRecibo()


CLASE BASE (C++) CLASE PADRE SUPERCLASE
4

HERENCIA Definicin
!

La herencia es el mecanismo de implementacin mediante el cual elementos ms especficos incorporan la estructura y comportamiento de elementos ms generales (Rumbaugh 99)
Gracias a la herencia es posible especializar o extender la funcionalidad de una clase, derivando de ella nuevas clases. La herencia es siempre transitiva: una clase puede heredar caractersticas de superclases que se encuentran muchos niveles ms arriba en la jerarqua de herencia.
!

Ejemplo: si la clase Perro es una subclase de la clase Mamfero, y la clase Mamfero es una subclase de la clase Animal, entonces el Perro heredar atributos tanto de Mamfero como de Animal.

HERENCIA Test ES-UN


!

La clase A se debe relacionar mediante herencia con la clase B si A ES-UN B. Si la frase suena bien, entonces la situacin de herencia es la ms probable para ese caso
! ! ! ! !

Un pjaro es un animal Un gato es un mamfero Un pastel de manzana es un pastel Una matriz de enteros es un matriz Un coche es un vehculo

HERENCIA Test ES-UN


!

Sin embargo, si la frase suena rara por una razn u otra, es muy probable que la relacin de herencia no sea lo ms adecuado. Veamos unos ejemplos:
! ! ! !

Un pjaro es un mamfero Un pastel de manzana es una manzana Una matriz de enteros es un entero Un motor es un vehculo

De todas formas, puede haber casos en los que este test puede fallar y sin embargo la relacin de herencia es evidente. Sin embargo, para la mayor parte de los casos, la aplicacin de esta tcnica es adecuada.

HERENCIA Principales usos


!

La herencia como reutilizacin de cdigo: Una clase derivada puede heredar comportamiento de una clase base, por tanto, el cdigo no necesita volver a ser escrito para la derivada. La herencia como reutilizacin de conceptos: Esto ocurre cuando una clase derivada sobrescribe el comportamiento definido por la clase base. Aunque no se comparte ese cdigo entre ambas clases, ambas comparten el prototipo del mtodo (comparten el concepto).

Clasificacin y generalizacin
!

La mente humana clasifica los conceptos de acuerdo a dos dimensiones:


! !

Pertenencia (TIENE-UN) -> Relaciones todo-parte Variedad (ES-UN) -> Herencia

La herencia consigue clasificar los tipos de datos (abstracciones) por variedad, acercando un poco ms el mundo de la programacin al modo de razonar humano.
! !

Este modo de razonar humano se denomina GENERALIZACIN, y da lugar a jerarquas de generalizacin/especializacin. La implementacin de estas jerarquas en un lenguaje de programacin da lugar a jerarquas de herencia.

Herencia como implementacin de la Generalizacin


!

La generalizacin es una relacin semntica entre clases, que determina que la interfaz de la subclase debe incluir todas las propiedades pblicas y privadas de la superclase. Disminuye el nmero de relaciones (asociaciones y agregaciones) del modelo Aumenta la comprensibilidad, expresividad y abstraccin de los sistemas modelados. Todo esto a costa de un mayor nmero de clases
11

Tipos de Herencia
! !

Simple/Mltiple De implementacin/de interfaz A nivel semntico, Bertrand Meyer distingue 17 tipos de herencia.

12

Tipos de Herencia
!

Simple/Mltiple
!

Simple: nica clase base

Mltiple: Ms de una clase base

13

Tipos de Herencia
!

De implementacin/de interfaz
!

De implementacin: La implementacin de los mtodos es heredada. Puede sobreescribirse en las clases hijas. De interfaz: Slo se hereda la interfaz, no hay implementacin a nivel de padre (interfaces en Java, clases abstractas en C++)

14

Herencia
!

Caracterizacin Atributos de la generalizacin


!

Solapada/Disjunta
!

Determina si un objeto puede ser a la vez instancia de dos o ms subclases de ese nivel de herencia. C++ no soporta la herencia solapada (tipado fuerte) Determina si todas las instancias de la clase padre son a la vez instancias de alguna de las clases hijas (completa) o, por el contrario, hay objetos de la clase padre que no pertenecen a ninguna subcategora de las reflejadas por las clases hijas (incompleta). A nivel de implementacin, una jerarqua de herencia completa suele implicar que la clase padre puede ser definida como abstracta (es decir, impedir que se creen instancias de ella). Determina si un determinado objeto puede pasar de ser instancia de una clase hija a otra dentro de un mismo nivel de la jerarqua de herencia. C++ no soporta la herencia dinmica (tipado fuerte)

Completa/Incompleta
!

Esttica/Dinmica
!

16

Herencia

Caracterizacin: ejemplos

17

HERENCIA
Herencia Simple

Herencia Simple en C++


class Figura2D { public: Figura2D(Coordenada posicion, Color c); ... Color getColor(); void setColor(Color c); private: Coordenada origen; Color colorRelleno; }; class Circulo : Figura2D { ... public: void vaciarCirculo() { colorRelleno=NINGUNO; // ERROR! colorRelleno es privado setColor(NINGUNO); // OK } };

int main() { Circulo c; c.setcolor(AZUL); c.getColor(); ... }


19

Herencia en C++
!

Visibilidad atributos/mtodos C++ introduce un nuevo mbito de visibilidad para el tratamiento de la herencia: protected
!

Los datos/funciones miembros protected son privados para todas aquellas clases no derivadas y mtodos externos, pero accesibles para una clase derivada de la clase en que se ha definido la variable protegida.
int main () { Circulo c; c.colorRelleno=NINGUNO; // ERROR! colorRelleno // es privado aqu }

class Figura2D {

...
protected: Color colorRelleno;

...
};

class Circulo : Figura2D { public: void vaciarCirculo() { colorRelleno=NINGUNO; //OK, protected } ... };
20

Tipos de Herencia Simple (en C++)


!

Herencia Pblica (por defecto)


class Circulo : public Figura2D { ... };
<<public>>

Herencia Protegida
class Circulo : protected Figura2D { ... };
<<protected>>

Herencia Privada
class Circulo : private Figura2D { ... };
<<private>>

21

Tipos de Herencia Simple


mbito Herencia Visibilidad en clase base

CD (*) H. Pblica No direct. accesible Protected Public

CD H. Protegida No direct. accesible Protected Protected

CD H. privada No direct. accesible Private Private

Private Protected Public

(*) CD: Clase derivada


22

Tipos Herencia Simple Ejercicio


Abuela
+ publico: int # protegido: int - privado: int + setPublicoAbuela(int) + setProtegidoAbuela(int) + setPrivadoAbuela(int) + inicializaTodoAUno();

Padre

<<??>>
+inicializaTodoAUno()

<<public>>
Hija

Implementa el mtodo Hija::inicializaTodoAUno() suponiendo que la herencia entre Abuela y Padre es: Pblica Protegida Privada

+inicializaTodoAUno()
23

Herencia Simple
!

En la clase derivada se puede:


!

AADIR nuevos mtodos/atributos propios de la clase derivada Modificar los mtodos heredados de la clase base ! REFINAR: se aade comportamiento nuevo antes y/o despus del comportamiento heredado. (Simula, Beta) (se puede simular en C++, Java) ! C++, Java: Constructores y destructores se refinan ! REEMPLAZAR: el mtodo heredado se redefine completamente, de forma que sustituye al original de la clase base.

25

El constructor en herencia simple


!

Los constructores no se heredan


! !

Siempre son definidos para las clases derivadas Creacin de un objeto de clase derivada: Se invoca a todos los constructores de la jerarqua Orden de ejecucin de constructores: Primero se ejecuta el constructor de la clase base y luego el de la derivada.

26

El constructor en herencia simple


!

Esto implica que la clase derivada aplica una poltica de refinamiento: aadir comportamiento al constructor del padre. Ejecucin implcita del constructor por defecto de clase base al invocar a un constructor de clase derivada. Ejecucin explcita de cualquier otro tipo de constructor en la zona de inicializacin (refinamiento explcito). En particular, el constructor de copia.
(CONSEJO: Inicializacin de atributos de la clase base: en la clase base, no en la derivada)

27

El destructor en herencia simple


!

El destructor no se hereda.
! !

Siempre es definido para la clase derivada Destruccin de un objeto de clase derivada: se invoca a todos los destructores de la jerarqua Primero se destruye el objeto derivado y luego el objeto base. Llamada implcita a los destructor de la clase base.

28

Construccion/destruccin en resumen
!

Los objetos se destruyen en orden inverso al de construccin.

29

Ejemplo Clase Base


TCuenta
# # # # titular: string saldo: double interes: double numCuentas: int

+ TCuenta() + TCuenta(TCuenta &) + operator=() + ~TCuenta() + getTitular() + getSaldo() + getInteres() + setSaldo() + setInteres() + abonarInteresMensual() + mostrar() <<friend>> operator<<()
30

Herencia Simple (base): TCuenta


class TCuenta{ public: TCuenta(string t, double s=0.0, double i=0.0) : titular(t), saldo(s), interes(i) { numCuentas++; } ... protected: string titular; double saldo; double interes; static int numCuentas; friend ostream& operator<<(ostream&, const TCuenta&); };
31

Herencia Simple (base): TCuenta (II)


TCuenta::TCuenta(const TCuenta& tc) : titular(tc.titular), saldo(tc.saldo), interes(tc.interes) { numCuentas++; } TCuenta& TCuenta::operator=(const TCuenta& tc) { if (this!=&tc) { titular = tc.titular; saldo=tc.saldo; interes=tc.interes; } return*this; } TCuenta::~TCuenta(){ numCuentas--; } string TCuenta::getTitular() const {return titular;}; double TCuenta::getSaldo() const {return saldo;}; double TCuenta::getInteres() const {return interes;}; void TCuenta::setSaldo(double s) {saldo=s;}; void TCuenta::setInteres(double i) {interes=i;};
32

Herencia Simple (base): TCuenta (III)


void TCuenta::abonarInteresMensual() { setSaldo(getSaldo()*(1+getInteres()/100/12)); }; friend ostream& operator<< (ostream& os, TCuenta& unaCuenta) { os << Titular= << unaCuenta.titular << endl; os << "Saldo= << unaCuenta.saldo << endl; os << Interes= << unaCuenta.interes << endl; os << NumCuentas= << TCuenta::numCuentas << endl; return os; } void TCuenta::mostrar (){ cout << *this; } }

33

Ejemplo clase derivada


TCuenta

TCuentaJoven
- int edad + + + + + + + + TCuentaJoven() TCuentaJoven(const TCuentaJoven&) ~TCuentaJoven() operator=(const TCuentaJoven&) : TCuenta& abonarInteresMensual() : void getEdad() : int setEdad(int) : void mostrar() : void

<<friend>> operator<<(ostream&,const TCuentaJoven&)

34

Herencia Simple (derivada): TCuentaJoven (I)


class TCuentaJoven: public TCuenta { private: Hay que incrementar int edad; numCuentas? public: TCuentaJoven(string unNombre,int unaEdad, double unSaldo=0.0, double unInteres=0.0) : TCuenta(unNombre,unSaldo,unInteres), edad(unaEdad) { } TCuentaJoven(const TCuentaJoven& tcj) // llamada explcita a constructor de copia de TCuenta. : TCuenta(tcj), edad(tcj.edad) { } ~TCuenta() { edad=0; } TCuenta& operator=(const TCuentaJoven& tcj) { if (this!=&tcj) { TCuenta::operator=(tcj); Refinamiento edad = tcj.edad; } return *this; }
35

Herencia Simple (derivada): TCuentaJoven (II)


void abonarInteresMensual() { if (getSaldo()>=10000) { setSaldo(getSaldo()*(1+getInteres()/12/100)); } } Reemplazo //no inters si el saldo es inferior al lmite

36

Herencia Simple (derivada): TCuentaJoven (III)


int getEdad(){return edad;}; void setEdad(int unaEdad){edad=unaEdad;};

Mtodos aadidos

void mostrar(){ TCuenta::mostrar(); Mtodo cout<<Edad:<<edad<<endl; Refinado } friend ostream& operator<< (ostream& os, TCuentaJoven& c){ os << Titular="<<c.titular<<endl; os << "Saldo="<<c.saldo<<endl; os << "Edad="<<c.edad<<endl; os << NumCuentas="<<TCuentaJoven::numCuentas<<endl; return os; } };//fin clase TCuentaJoven

Cmo podrais definir el operador << para que fuese inmune a los cambios en la clase base y adems ocupase menos lneas de cdigo? Qu est ocurriendo con el nmero de cuentas? Hace falta incrementar el numCuentas?
37

Ejercicio: TCuentaEmpresarial
TCuenta

TCuentaEmpresarial TCuentaJoven
- nomEmpresa: char*

Cmo se definira una clase TCuenta Empresarial, que tambin heredara de TCuenta?

+ TCuentaEmpresarial() + TCuentaEmpresarial(TCuentaEmpresarial&) + ~TCuentaEmpresarial() + abonarInteresMensual():void + getNomEmpresa(): char* + mostrar():void <<friend>> operator<< (ostream&,...)

39

Particularidades Herencia
!

Como ya hemos visto, en las jerarquas de herencia hay un refinamiento implcito de:
! !

Constructor por defecto Destructores

Las variables estticas definidas en la clase base tambin son compartidas (heredadas) por las clases derivadas. El operador de asignacin (Tema 4) tampoco se mantiene como mtodo fundacional (es decir, reutilizable sin cambios) en la jerarqua, sino que se sustituye siempre por uno propio de la clase derivada (puede ser de oficio, proporcionado por el compilador). De ah que la forma cannica de la clase implique siempre definir estas cuatro funciones miembro Se heredan las funciones amigas?
40

Ejercicio Propuesto
!

Definid una jerarqua de herencia en la que se contemplen los empleados de una empresa, almacenando su nombre y su sueldo, y los gerentes como un tipo especial de empleados de los que almacenaremos el departamento y el nombre de su secretaria. Realizar la especificacin UML y el .h de las clases implicadas.

41

HERENCIA
Herencia Mltiple

Ejemplo Herencia Mltiple


class TEmpresa{ TCuenta TEmpresa protected: char *nomEmpresa; public: TEmpresa(const char* unaEmpresa) { nomEmpresa=new char[strlen(unaEmpresa)+1] ; strcpy(nomEmpresa,unaEmpresa); TCuentaEmpresarial }; void setNombre(char *nuevoNombre) { if (nomEmpresa!=NULL) delete [] nomEmpresa; nomEmpresa=new char[strlen(nuevoNombre)+1]; strcpy(nomEmpresa,nuevoNombre);} ~TEmpresa() { delete [] nomEmpresa; } }; Cmo implementar TCuentaEmpresarial?
43

Ejemplo Herencia Mltiple (II)


class TCuentaEmpresarial : public TCuenta, public TEmpresa { public: TCuentaEmpresarial(const char *unNombreCuenta, const char *unNombreEmpresa, double unSaldo=0, double unInteres=0) :TCuenta(unNombreCuenta,unSaldo,unInteres), TEmpresa(unNombreEmpresa) {}; };

44

Problemas en Herencia Mltiple

TCuenta

TEmpresa

(1) Clase Abuela (2)

TCuentaEmpresarial

Clase Madre1

Clase Madre2

Clase Hija Qu problemas pueden darse en (1)? Y en (2)?


45

Uso de mbito en Herencia Mltiple


class TCuentaEmpresarial: public TCuenta, public TEmpresa{ string n; if n= TCuenta::getNombre(); else n= TEmpresa::getNombre(); }

46

Herencia virtual (Herencia mltiple)


class Madre_1: virtual public Abuela{ } class Madre_2: virtual public Abuela{ } class Hija: public Madre_1, public Madre_2 { Hija() : Madre_1(), Madre_2(), Abuela(){ }; }

47

HERENCIA
Herencia de Interfaz

Herencia de interfaz
! ! !

La herencia de interfaz NO hereda cdigo Es una herencia sin efectos secundarios. Se utiliza exclusivamente con el propsito de garantizar la sustituibilidad.

50

El principio de sustitucin
Debe ser posible utilizar cualquier objeto instancia de una subclase en el lugar de cualquier objeto instancia de su superclase sin que la semntica del programa escrito en los trminos de la superclase se vea afectado. (Liskov !"#$%
Subtipo& Una clase B, subclase de A, es un subtipo de A si podemos sustituir instancias de A por instancias de B en cualquier situacin y sin ningn efecto observable.

POO 2007-2008

El principio de sustitucin

Todos los LOO soportan subtipos


Lengua!es fuertemente tipados "tipado est#tico$

%aracteri&an los ob!etos por su clase %aracteri&an los ob!etos por su comportamiento
Lengua!e debilmente tipado' funcion medir(objeto) { si (objeto <= 5) sino si (objeto == 0) ...}

Lengua!es debilmente tipados "tipado din#mico$

Lengua!e fuertemente tipado' funcion medir(objeto: Medible) {...}

POO 2007-2008

El principio de sustitucin

C++' (ubtipos slo a trav)s de punteros o referencias

Java' directamente

class Dependiente { public: int cobrar(); void darRecibo(); ...}; class Panadero : public Dependiente {...}

class Dependiente { public int cobrar(); public void darRecibo(); ...}; class Panadero e$tends Dependiente {...} Panadero p = ne% Panadero(); Dependiente d1=p; // sustit.

Panadero p; Dependiente& d1=p; // sustit. Dependiente* d =&p; // sustit. POO 2007-2008 Dependiente d!=p; // "# sustit.

*E+E,%-A .E -,TE+/A0

Objetivos:

+eutili&acin de conceptos "interfa&$ 1aranti&ar que se cumple el principio de sustitucin

-mplementacin mediante clases abstractas "%22$ o interfaces "3ava4%5$

POO 2007-2008

*E+E,%-A .E -,TE+/A0

Clases abstractas

(on clases en las que alguno de sus m)todos no est# definido "m)todos abstractos$ ,o se pueden crear ob!etos de estas clases (6 se pueden crear referencias "o punteros$ a ob!eto de una clase abstracta "que apuntar#n a ob!etos de clases derivadas$

7ropsito' 1aranti&ar que las clases derivadas proporcionan una implementacin propia de ciertos m)todos (ustituibilidad' (e garanti&a la sustituibilidad
POO 2007-2008

*E+E,%-A .E -,TE+/A0

Clases abstractas

Las clases que deriven de clases abstractas "o interfaces$ deben implementar todos los m)todos abstractos "o ser#n a su ve& abstractas$ La clase derivada implementa el interfa& de la clase abstracta

POO 2007-2008

*E+E,%-A .E -,TE+/A0
,otacin U8L para clases abstractas

Vehculo

CLASE ABSTRACTA

CLASE ABSTRACTA
Terrestre {abstract}

CLASE ABSTRACTA

Areo

Coche

Bicicleta

Avin

Helicptero

CLASES CONCRETAS
POO 2007-2008

*E+E,%-A .E -,TE+/A0

%lases abstractas en %22

%lases que contiene al menos un metodo virtual puro "m)todo abstracto$'


%lase abstracta %lase derivada class /irculo : public *or(a { int radio; public: void dibu-ar() {...}; ... }

virtual &tipo devuelto' (etodo(&lista ar)s') = 0;


class *or(a { int pos$+ pos,; public: virtual void dibu-ar()= 0; int )etPosicion.() { return pos$; } ... }

POO 2007-2008

*E+E,%-A .E -,TE+/A0

%lases abstractas en 3ava


abstract class { ... abstract &tipo devuelto' (etodo(&lista ar)s'); }
%lase abstracta

abstract class *or(a { private int pos$+ pos,; public abstract void dibu-ar(); public int )etPosicion.() { return pos$; } ... }

%lase derivada class /irculo e$tends *or(a { private int radio; public void dibu-ar() {...}; ... }

POO 2007-2008

*E+E,%-A .E -,TE+/A0

Interfaces

.eclaracin de un con!unto de m)todos sin definir En %22, son clases abstractas donde ningn m)todo est# definido 3ava4%5' declaracin e9pl6cita de interfaces

Las clases pueden implementar m#s de un interfa& ":erencia mltiple de interfaces$


POO 2007-2008

*E+E,%-A .E -,TE+/A0
,otacin U8L para interfaces
<<interface>>

Vehculo

INTERFAZ

CLASE ABSTRACTA
Terrestre {abstract}

CLASE ABSTRACTA

Areo

Coche

Bicicleta

Avin

Helicptero

CLASES CONCRETAS
POO 2007-2008

*E+E,%-A .E -,TE+/A0

Interfaces en Java

interface *or(a { // 0 1in atributos de instancia // 0 12lo constantes est3ticas // 0 4odos los (5todos son abstractos void dibu-ar(); int )etPosicion.(); ... } class /irculo implements *or(a { private int pos$+ pos,; private int radio; public void dibu-ar() {...}; public int )etPosicion.() {...}; POO 2007-2008 }

*E+E,%-A .E -,TE+/A0

Interfaces en C22

class *or(a { // 0 1in atributos de instancia // 0 12lo constantes est3ticas // 0 4odos los (5todos son abstractos void dibu-ar()=0; int )etPosicion.()=0; // resto de (5todos virtuales puros... } class /irculo : public *or(a // 6erencia p7blica { private: int pos$+ pos,; int radio; public: void dibu-ar() {...} int )etPosicion.() {...}; POO 2007-2008 }

*E+E,%-A .E -,TE+/A0

E!emplo de interfa& "3ava$


;;interface<< %omparable inter8ace /o(parable { int co(pare4o(/o(parable o); } class 9ntero i(ple(ents /o(parable { private int n; 9ntero(int i) { n=i; } Entero public int co(pare4o(/o(parable e) { 9ntero e =(9ntero)e; i8 (e .n ' n) return 01; else i8 (e .n == n) return :; return 1; }
POO 2007-2008

compareTo"%omparable$ ' int

compareTo"%omparable$ ' int

*E+E,%-A .E -,TE+/A0

E!emplo de clase abstracta "%22$


TCuentaVirtual 5 nombre 5 saldo 5 inter)s 5 num%uentas TCuentaVirtual

TCuentaJoven edad' int

2 T%uenta=irtual"$ 2 T%uenta=irtual"T%uenta=irtual$ 2 T%uenta3oven"$ 2 >T%uenta"$ 2 T%uenta3oven"T%uenta3oven$ 2 get,ombre"$ const 2 >T%uenta3oven"$ 2 get(aldo"$ const 2 getEdad"$' int 2 get-nteres"$ const 2 setEdad"int$' void 2 set(aldo"$ +abonarInteresMensual(): void 2 set-nteres"$ 2mostrar"$ +abonarInteresMensual(): void ;;friend<< operator;;"$ 2mostrar"$ ;;friend<< operator;;"$ POO 2007-2008

*E+E,%-A .E -,TE+/A0
class 4/uenta;irtual { protected: ... public: ... virtual void abonarInteresMensual()=0; }; class 4/uenta<oven: public 4/uenta;irtual{ private: int edad; public: ... // =>P?9>9"4@/=#" void abonarInteresMensual(){ //no inter5s si el saldo es in8erior al lA(ite i8 ()et1aldo()'=1::::){ set1aldo()et1aldo()*(1B)et=nteres()/1 /1::)); } }; POO 2007-2008 // si)ue...

*E+E,%-A .E -,TE+/A0
// si)ue... void (ostrar(){ 4/uenta;irtual::(ostrar(); cout&&C9dad:C&&edad&&endl; } 8riend ostrea(& operator&&(ostrea(& os+ 4/uenta<oven& c){ // os&&(4/uenta;irtual)c&&endl; // ERROR cast a clase abstracta c.4/uenta;irtual::(ostrar(); // Proble(a: (ostrar() usa cout os && C9dad=C&&una/uenta.edad&&endl; return os; }

('ncuentra el modo de reutilizar el c(digo del operador de salida de la clase )*uenta+irtual POO 2007-2008 en el operador de salida de )*uenta,oven%

8etodos virtuales y sobreescritura


... 4/uenta;irtual* tcv; tcv = ne% 4/uenta<oven; tcv!"abonarInteresMensual(); // ?la(ada a #$uenta%oven abonarInteresMensual() delete tcv; // DE ...

La clase derivada redefine el comportamiento de la clase base (e pretende invocar a ciertos m)todos redefinidos desde referencias a ob!etos de la clase base "principio de sustitucin$

En %22 es necesario indicar e9pl6citamente que dic:a sustitucin es posible mediante la definicin de dic:os m)todos como virtuales "mediante la palabra clave virtual$ En muc:os lengua!es OO este rasgo es soportado de forma natural' 7or e!emplo, en 3ava, los m)todos son virtuales por defecto (obreescritura' redefinicin de m)todos virtuales en clases derivadas POO 2007-2008

8etodos virtuales y sobreescritura


class 4/uenta;irtual { virtual void abonar=nteres>ensual(); virtual void set=nteres(8loat i); virtual &#$uenta'irtual(); }

(i una clase tiene m)todos virtuales Es posible utili&ar el principio de sustitucin' *eredar de ella y sobreescribir los m)todos virtuales El destructor de esta clase base debe declararse como m)todo virtual
POO 2007-2008

E!ercicio' 7ago de ,minas


TEmpleado string nombre

TFijo double sueldo 2 T/i!o"$ 2 T/i!o"T/i!o @$ 2 >T/i!o"$ 2 set(ueldo"$

TComisionista double base, comisin, ventas? 2 T%omisionista"$ 2 T%omisionista"T%omisionista @$ 2 >T%omisionista"$ 2 set%omisin"$ 2 get%omisin"$ const 2 setBase"$ 2 getBase"$ const
POO 2007-2008

E!ercicio' 7ago de ,minas


-mplementa las clases anteriores aAadiendo un m)todo get(alario"$, que en el caso del empleado fi!o devuelve el sueldo y en el caso del comisionista devuelve la base m#s la comisin, de manera que el siguiente cdigo permita obtener el salario de un empleado independientemente de su tipo

int (ain(){ int tipo; 9(pleado *eptr; cout&&F=ntroduce tipoG&&endl; cin''tipo; //1:8i-o+ co(isionista s%itcH (tipo){ case 1: eptr=ne% *i-o(); breaI; case :eptr=ne% /o(isionista(); breaI; } eptr0')et1alario(); delete eptr; }
POO 2007-2008

HERENCIA
Herencia de Implementacin

Herencia de implementacin
!

Habilidad para que una clase herede parte o toda su implementacin de otra clase. Debe ser utilizada con cuidado.

72

Uso seguro de la herencia de implementacin


!

En la herencia existe una tensin entre expansin (adicin de mtodos ms especficos) y contraccin (especializacin o restriccin de la clase padre) Esta tensin est en la base de su poder, y tambin de los problemas asociados con su uso. En general, la redefinicin de mtodos slo debera usarse para hacer las propiedades ms especficas
! !

Constreir restricciones Extender funcionalidad

73

Uso seguro de la herencia de implementacin


!

Especializacin
!

La clase derivada es una especializacin de la clase base: aade comportamiento pero no modifica nada
! !

Satisface las especificaciones de la clase base Se cumple el principio de sustitucin (subtipo)


Ventana mostrar()

VentanaDeTexto editar()
74

Uso seguro de la herencia de implementacin


!

Especificacin
!

La clase derivada es una especificacin de una clase base abstracta o interfaz.


!

! !

Implementa mtodos no definidos en la clase base (mtodos abstractos o diferidos). No aade ni elimina nada. La clase derivada es una realizacin (o implementacin) de la clase base.
Pila {abstract} apila(Object) : void desapila() : Object tope() : Object

PilaDeEnteros
apila(Object) : void desapila() : Object tope() : Object

75

Uso inseguro de la herencia de implementacin


!

Restriccin (limitacin)
Pjaro Volar()

No todo lo de la clase base sirve a la derivada. Hay que redefinir ciertos mtodos para eliminar comportamiento presente en la clase base

Pingino Nadar()

No se cumple el principio de sustitucin (un pingino no puede volar)


76

Uso inseguro de la herencia de implementacin


!

Generalizacin
Ventana Coordenada_x Coordenada_y Mover()

Se extiende el comportamiento de la clase base para obtener un tipo de objeto ms general. Usual cuando no se puede modificar la clase base. Mejor invertir la jerarqua.

VentanaColor colorFG colorBG setColorFG() getColorFG()

77

Uso inseguro de la herencia de implementacin


!

Varianza (herencia de conveniencia)


Punto Coordenada_x Coordenada_y Mover()

La implementacin se parece pero semnticamente los conceptos no estn relacionados jerrquicamente (test es-un). INCORRECTA!!!!

Lnea direccion setDireccion()

Solucin: si es posible, factorizar cdigo comn. (p.ej. Ratn y Tableta_Grafica)

78

Herencia de Construccin
!

Una clase hereda pate de su funcionalidad de otra, modificando el interfaz heredado La clase derivada no es una especializacin de la clase base (puede que incluso no haya relacin esun)
! !

No se cumple el principio de sustitucin (ni se pretende) P. ej., una Pila puede construirse a partir de un Array
Array elementoAt(int i) : Object capacidad() : int numElementos() : int

Pila
apila(Object) : void desapila() : Object tope() : Object

79

Herencia de Construccin en C++


!

La herencia privada en C++ implementa un tipo de herencia de construccin que s preserva el principio de sustitucin: tambin conocida como Herencia de Implementacin Pura
!

El hecho de que Pila herede de Array no es visible para el cdigo que usa la pila.
!

La herencia se convierte en una decisin de implementacin.


Array

Pila
<<private>> apila(Object) : void desapila() : Object tope() : Object

elementoAt(int i) : Object capacidad() : int numElementos() : int

80

HERENCIA
Beneficios y costes de la herencia

Beneficios de la Herencia
! ! ! ! ! ! !

Reusabilidad software Comparticin de cdigo Consistencia de interface Construccin de componentes Prototipado rpido Polimorfismo Ocultacin de informacin

[BUDD] 8.8
82

Costes de la Herencia
! ! ! !

Velocidad de ejecucin Tamao del programa Sobrecarga de paso de mensajes Complejidad del programa

[BUDD] 8.9
83

HERENCIA
Eleccin de tcnica de reuso

Herencia vs Todo-Parte
!

Herencia es una relacin entre clases, mientras que Agregacin/Composicin es una relacin entre objetos
! !

Herencia es menos flexible Donde se detecta una relacin HAS-A no siempre es posible cambiarla por una relacin de herencia. Sin embargo, donde se detecta una relacin de herencia, siempre es posible reformularla para que se convierta en una relacin de composicin.
! ! !

Un programador de C++ es un programador Todo programador de C++ tiene un programador en su interior Todo programador de C++ tiene una vocacin de programar en su interior

Regla del cambio: no se debe usar herencia para describir una relacin IS-A si se prev que los componentes puedan cambiar en tiempo de ejecucin (si preveo que pueda cambiar mi vocacin ").
!

Las relaciones de composicin se establecen entre objetos, y por tanto permiten un cambio ms sencillo del programa.

Regla del polimorfismo: la herencia es apropiada para describir una relacin IS-A cuando las entidades o los componentes de las estructuras de datos del tipo ms general pueden necesitar relacionarse con objetos del tipo ms especializado (e.g. por reuso).
85

Eleccin de tcnica de reuso Introduccin


!

Herencia (IS-A) y Composicin (HAS-A) son los dos mecanismos ms comunes de reuso de software
!

COMPOSICIN (Layering): Relacin tener-un: ENTRE OBJETOS.


! !

Composicin significa contener un objeto. Ejemplo: Un coche tiene un tipo de motor.

class coche {... private: Motor m; }; HERENCIA: Relacin ser-un: ENTRE CLASES
! !

Herencia significa contener una clase. Ejemplo: Un coche es un vehculo

class coche: public vehiculo{ }


86

Eleccin de tcnica de reuso Introduccin


!

Ejemplo: construccin del tipo de dato Conjunto a partir de una clase preexistente Lista
class Lista{
public: Lista(); //constructor void add (int el); int firstElement(); int size(); int includes(int el); void remove (int pos);

};
!

Queremos que la nueva clase Conjunto nos permita aadir un valor al conjunto, determinar el nmero de elementos del conjunto y determinar si un valor especfico se encuentra en el conjunto.
87

Eleccin de tcnica de reuso Uso de Composicin (Layering)


!

Un objeto es una encapsulacin de datos y comportamiento. Por tanto, si utilizamos la Composicin estamos diciendo que parte del estado de la nueva estructura de datos es una instancia de una estructura existente
class Conjunto{ public: //constructor debe inicializar el objeto Lista Conjunto():losDatos(){}; int size(){return losDatos.size();}; int includes (int el){return losDatos.includes(el);}; //un conjunto no puede contener valor ms de una vez void add (int el){ if (!includes(el)) losDatos.add(el); }; private: Lista losDatos; };

88

Eleccin de tcnica de reuso Uso de Composicin (Layering)


!

La composicin proporciona un mecanismo para reutilizar un componente software existente en la creacin de una nueva aplicacin, simplificando su implementacin La composicin no realiza ninguna asuncin respecto a la sustituibilidad. Cuando se forma de esta manera, un Conjunto y una Lista son tipos de datos totalmente distintos, y se supone que ninguno de ellos puede sustituir al otro en ninguna situacin. La composicin se puede aplicar del mismo modo en cualquier lenguaje OO e incluso en lenguajes no OO.

89

Eleccin de tcnica de reuso Uso de Herencia


!

Con herencia una clase nueva puede ser declarada como una subclase de una clase existente, lo que provoca que todas las reas de datos y funciones asociadas con la clase original se asocien automticamente con la nueva abstraccin de datos.
class Conjunto : public Lista{ public: Conjunto() : Lista() {}; //un conjunto no puede contener valor ms de una vez void add (int el){ //refinamiento if (!includes(el)) Lista::add(el); }; };

Implementamos en trminos de clase base (no objeto) ! No existe una lista como dato privado Las operaciones que actan igual en la clase base y en la derivada no deben ser redefinidas (con composicin s).

90

Eleccin de tcnica de reuso Uso de Herencia


!

El uso de la herencia asume que las subclases son adems subtipos.


!

As, las instancias de la nueva abstraccin deberan comportarse de manera similar a las instancias de la clase padre.

91

Eleccin de tcnica de reuso Composicin vs. Herencia


!

La composicin es una tcnica generalmente ms sencilla que la herencia.


!

Define ms claramente la interfaz que soporta el nuevo tipo, independientemente de la interfaz del objeto parte. Problema del yo-yo: En la herencia las operaciones de la clase hija son un superconjunto de las de la clase padre, por lo que el programador debe examinar todas las clases en la jerarqua para conocer qu operaciones son legales para la nueva estructura.

La composicin es ms flexible (y ms resistente a los cambios)


!

La composicin slo presupone que el tipo de datos X se utiliza para IMPLEMENTAR la clase C. Es fcil por tanto:
!

Dejar sin implementar los mtodos que, siendo relevantes para X, no lo son para la nueva clase C Reimplementar C utilizando un tipo de datos X distinto sin impacto para los usuarios de la clase C.
92

Eleccin de tcnica de reuso Composicin vs. Herencia


!

La herencia presupone el concepto de subtipo (principio de sustitucin)


!

La herencia permite una definicin ms escueta de la clase


! !

Requiere menos cdigo. Oferta ms funcionalidad: cualquier nuevo mtodo asociado al padre estar inmediatamente disponible para todos sus hijos

! !

Soporta directamente el principio de sustitucin (composicin no) La herencia es ligeramente ms eficiente que la composicin (evita una llamada). Los usuarios pueden manipular la nueva estructura mediante mtodos de la clase base, incluso si stos no son apropiados. Cambiar la base de una clase puede causar muchos problemas a los usuarios de dicha clase.
93

Desventajas
!

Eleccin de tcnica de reuso Ejemplos Composicin vs. Herencia


!

Clase Persona y clase Empleado


!

Herencia: un empleado es una persona. Composicin: una persona tiene un domicilio Composicin: una lista tiene un puntero de tipo nodo al nodo que est en cabeza de la lista (tener-un).

Clase Persona y clase Domicilio


!

Clase Lista y clase Nodo de la lista


!

Clase Empresa, clase Empleado y clase Jefe de grupo de empleados


! !

Herencia entre empleado y jefe: Un jefe es un empleado Composicin entre empresa y empleado (o empleado y jefe):
! !

Un empresa puede tener una lista de empleados y otra de jefes Por el principio de los subtipos, una empresa puede tener un nica lista donde aparezcan tanto los jefes como empleados.
94

Eleccin de tcnica de reuso Ejercicio: Visualizador de documentos


!

Suponed que tenemos una estructura genrica de documento, y que queremos visualizar instancias de documentos con esa estructura en distintos formatos (HTML, PDF, DOC, etc.).

Cmo implementarais un sistema que soportara esta visualizacin?

95

Eleccin de tcnica de reuso Solucin: Visualizador de documentos


Documento Genrico Formateador Especfico Documento Genrico

Documento Documento HTML PDF DOC 1..1 Formateador Especfico

Con cul de las dos soluciones

sera posible modificar el modo de visualizacin del documento? Con cul se cumplira el dicho Una HTML vez documento HTML, siempre documento web?
PDF DOC

96

Eleccin de tcnica de reuso Ejercicio: Videoclub Videoclub: Un videoclub dispone de una serie de pelculas que pueden estar en DVD o en VHS (una sola cinta por pelcula). De las pelculas interesa guardar el ttulo, el autor, el ao de edicin y el idioma (o los idiomas, en caso de DVD). El precio de alquiler de las pelculas vara en funcin del tipo de pelcula. ! Qu clases implementarais y cmo las relacionarais?
!

97

Eleccin de tcnica de reuso Solucin: Videoclub


!

Mediante herencia:

Pelcula

DVD

VHS

Cambiar de VHS a DVD supondra eliminar la instancia de pelcula y volverla a crear (la herencia es una relacin inmutable entre clases). Donde trabajaba con instancia de VHS (e.g. visualizar) ahora tengo que trabajar con instancias de DVD.

98

Eleccin de tcnica de reuso Solucin: Videoclub


!

Mediante composicin:
Pelcula

1..1 0..1
DVD

1..1 0..1
VHS

Ms flexible, ya que composicin implica una relacin a nivel de objeto (no de clase). Cmo indico que tengo que tener un DVD o un VHS?

0..1 o 1..1 siempre

99

Eleccin de tcnica de reuso Solucin: Videoclub


!

Mediante composicin y herencia:


Pelcula 1..1 Soporte

DVD

VHS

Ahora si yo renuevo mi parque de pelculas y cambio las VHS por DVD no hay ningn problema, puesto que puedo trabajar con instancias de soporte (e.g. visualizar), y ambos son subtipos de soporte. Se aprovechan las caractersticas de la herencia, y se aade flexibilidad.

100

Eleccin de tcnica de reuso Ejercicio: Videoclub con varias copias Qu cambios habra que realizar en una y otra solucin si el crecimiento de mi videoclub aconsejara tener varias copias de una misma pelcula?

101

Eleccin de tcnica de reuso Solucin: Videoclub con varias copias


Agregacin en lugar de composicin
Pelcula 1..n Soporte Pelcula

1..1 0..n
DVD

1..1 0..n
VHS

Pelcula

DVD

VHS DVD VHS

102

HERENCIA
EJERCICIOS

Relaciones entre Clases y Objetos


Ejercicio 1
!

Dibujad un diagrama de clases que muestre las dos categoras que existen de Clientes de una empresa: Clientes externos, que son otras compaas, y Clientes internos, que son todas las divisiones de dentro de la empresa. Suponed ahora que Divisin (cuyas instancias son las distintas divisiones de la empresa) es una clase del sistema. Cambiara en algo vuestra solucin?

105

Relaciones entre Clases y Objetos


Ejercicio 1: Solucin

Cliente Interno Externo

Divisiones Interno

Cliente Externo
106

Relaciones entre Clases y Objetos


Ejercicio 2
!

Dibujad un diagrama de clases que muestre la estructura de un captulo de libro; un captulo est compuesto por varias secciones, cada una de las cuales comprende varios prrafos y figuras. Un prrafo incluye varias sentencias, cada una de las cuales contiene varias palabras.
!

Suponed que en un futuro se prev que el sistema gestione adems de prrafos y figuras otros componentes, como tablas, listas, vietas, etc. Suponed adems que una palabra puede aparecer en varias sentencias.

107

Relaciones entre Clases y Objetos


Ejercicio 2: Solucin

Captulo

0..N {ordered}

Seccin

0..N {ordered}

Componente Seccin Imagen

Prrafo
0..N {ordered}

Sentencia
0..N 0..N {ordered}

Palabra
108

Relaciones entre Clases y Objetos


Ejercicio 3
!

Se desea desarrollar un sistema de nmina para los trabajadores de una empresa. Los datos personales de los trabajadores son Nombre y Apellidos, Direccin, DNI. Existen diferentes tipos de trabajadores: ! Fijos Mensuales: que cobran una cantidad fija al mes ! Comisionistas: cobran un porcentaje fijo por las ventas que han realizado ! Por Horas: cobran un precio por cada una de las horas que han realizado durante el mes. El precio es fijo para las primeras 40 horas y es otro para las horas realizadas a partir de la 40 hora mensual. ! Jefe: cobra un sueldo fijo (no hay que calcularlo) Cada empleado tiene obligatoriamente un jefe (exceptuando los jefes que no tienen ninguno). El programa debe permitir dar de alta trabajadores, fijar sus emolumentos, horas o ventas realizadas e imprimir la nmina correspondiente al final de mes.
109

Relaciones entre Clases y Objetos


Ejercicio 3: Solucin
Trabajador DNI nombre apellidos direccin New Destroy imprimirNmina

Jefe sueldo New Destroy 1..1 1..*

Empleado New Destroy calcularSueldo

PorHoras Comisionista FijoMensual sueldo New Destroy modificarSueldo comisin% ventas New Destroy modificarComisin modificarVentas precioHora precioHoraExtra horas New Destroy modificarPrecioHora modificarPrecioHorasExtras modificarHoras

110

Resumen
!

Una de las claves del poder de la programacin orientada a objetos es lograr la reutilizacin del software a travs de la herencia. El programador puede designar que la nueva clase herede los datos miembro y funciones miembro de una clase base definida previamente. En este caso, la clase nueva se conoce como clase derivada. En la herencia simple, una clase se deriva a partir de una sola clase base. En la herencia mltiple, una clase derivada hereda de varias clases base (que posiblemente no tengan relacin entre ellas). Una clase derivada por lo general agrega sus propios datos miembro y funciones miembro, por lo que comnmente tiene una definicin mayor que su clase base. Una clase derivada es ms especfica que su clase base y por lo general representa menos objetos. Una clase derivada no puede acceder a los datos miembro private de su clase base; permitirlo violara el encapsulamiento de la clase base. Sin embargo, una clase derivada puede acceder a los datos miembro public y protected de su clase base. Un constructor de clase derivada siempre llama primero al constructor de su clase base, para que cree e inicialice los miembros de clase base de la clase derivada.
111

Resumen
!

Los destructores se invocan en el orden inverso al de las llamadas de constructor, por lo que el destructor de la clase derivada se invoca antes que el destructor de su clase base. La herencia permite la reutilizacin del software, la cual ahorra tiempo en el desarrollo y promueve el empleo de software de alta calidad previamente probado y depurado. La herencia se puede hacer a partir de bibliotecas de clases ya existentes. Algn da, la mayor parte del software se construir a partir de componentes reutilizables estandarizados, de la misma manera que se construye la mayor parte del hardware. El implementador de una clase derivada no necesita acceder al cdigo fuente de su clase base, pero s necesita interactuar con la clase base y el cdigo objeto de la clase base. Un objeto de una clase derivada puede ser tratado como objeto de su clase base pblica correspondiente. Sin embargo, lo opuesto no es cierto. Una clase base existe en una relacin jerrquica con sus clases derivadas simples.
112

Resumen
!

Una clase puede existir por s sola. Cuando se utiliza dicha clase con el mecanismo de herencia, se vuelve una clase base que suministra atributos y comportamientos a otras clases o se vuelve una clase derivada que hereda esos atributos y comportamientos. Las jerarquas de herencia pueden tener una profundidad arbitraria dentro de las limitaciones fsicas de su sistema particular. Las jerarquas son herramientas tiles para entender y administrar la complejidad. Ahora que el software se vuelve cada vez ms complejo, C++ ofrece mecanismos para manejar estructuras jerrquicas mediante herencia y polimorfismo. Es posible utilizar una conversin mediante cast explcita para convertir un apuntador de clase base en apuntador de clase derivada. Tal apuntador no se debe desreferenciar, a menos que en realidad apunte a un objeto del tipo de la clase derivada. El acceso protected sirve como nivel intermedio de proteccin entre el acceso public y el acceso private. Los miembros y friend de la clase base y los miembros y friend de las clases derivadas pueden acceder los miembros protected de una clase base; ninguna otra funcin puede acceder a los miembros protected de una clase base.
113

Resumen
!

Los miembros protected se utilizan para extender los privilegios a las clases derivadas, negando dichos privilegios a las funciones que no son de la clase ni son friend. La herencia mltiple se indica poniendo dos puntos (:) a continuacin del nombre de la clase derivada y luego una lista separada por comas de clases base. Para llamar a los constructores de la clase base, se emplea sintaxis de inicializador de miembros en el constructor de la clase derivada. Cuando se deriva una clase a partir de una clase base, sta se puede declarar como public, protected o private. Cuando se deriva una clase a partir de una clase base public, los miembros public de sta se vuelven miembros public de la clase derivada y los miembros protected de la clase base se vuelven miembros protected de la clase derivada. Cuando se deriva una clase a partir de una clase base protected, los miembros public y protected de sta se vuelven miembros protected de la clase derivada. Cuando se deriva una clase a partir de una clase base private, los miembros public y protected de sta se vuelven miembros private de la clase derivada.
114

Resumen
!

Una clase base puede ser una clase base directa o indirecta de una clase derivada. Una clase base directa es aqulla que se lista explcitamente cuando se declara la clase derivada. Una clase base indirecta no se lista explcitamente; en cambio, se hereda de varios niveles ms arriba en el rbol jerrquico. Cuando un miembro de la clase base es inadecuado para una clase derivada, simplemente se redefine dicho miembro en la clase derivada. Es importante distinguir entre las relaciones "es un" y "tiene un". En las relaciones "tiene un", un objeto de clase tiene como miembro un objeto de otra clase. En las relaciones "es un", un objeto de un tipo de clase derivada tambin puede ser tratado como objeto del tipo de la clase base. "Es un" significa herencia. "Tiene un" significa composicin. Es posible asignar un objeto de clase derivada a un objeto de clase base. Este tipo de asignacin tiene sentido, pues la clase derivada tiene miembros que corresponden a cada uno de los miembros de la clase base. Es posible convertir implcitamente un apuntador a un objeto de clase derivada en apuntador a un objeto de clase base.
115

Resumen
!

Es posible convertir un apuntador de clase base en apuntador de clase derivada mediante una conversin cast explcita. El destino debe ser un objeto de clase derivada. Una clase base especifica comunidad. Todas las clases derivadas de una clase base heredan las capacidades de sta. En el proceso de diseo orientado a objetos, el diseador busca la comunidad y la factoriza para formar clases base deseables. Despus las clases derivadas se personalizan ms all de las capacidades heredadas de la clase base. La lectura de un conjunto de declaraciones de clase derivada puede ser confusa, pues no todos los miembros de la clase derivada estn presentes en dichas declaraciones. En particular, los miembros heredados no se listan en las declaraciones de las clases derivadas, pero estos miembros de hecho estn presentes en las clases derivadas. Las relaciones "tiene un" son ejemplos de la creacin de clases nuevas por medio de composicin de clases ya existentes. Las relaciones "conoce un" son ejemplos de objetos que contienen apuntadores o referencias a otros objetos, por lo que estn conscientes de ellos.
116

Resumen
!

Los constructores de objetos miembro se invocan en el orden en que se declaran los objetos. En la herencia, los constructores de clase base se invocan en el orden en que se especifica la herencia y antes del constructor de la clase derivada. En el caso de un objeto de clase derivada, primero se invoca al constructor de la clase base y luego al de la clase derivada (que puede llamar a constructores de objetos miembro). Cuando se destruye el objeto de la clase derivada, se invocan los destructores en el orden inverso al de los constructores: primero se llama al destructor de la clase derivada, luego al de la clase base. Es posible derivar una clase a partir de ms de una clase base; tal derivacin se llama herencia mltiple. La herencia mltiple se indica poniendo a continuacin del carcter de dos puntos (:), que indica herencia, una lista separada por comas de clases base. El constructor de la clase derivada llama a los constructores de las distintas clases base por medio de la sintaxis de inicializador de miembros. Los constructores de clases base se invocan en el orden en que se declaran las clases base durante la herencia.
117

También podría gustarte