Documente Academic
Documente Profesional
Documente Cultură
Contenido
Clase base Clase derivada Tipos de derivaciones Herencia simple Redefinir miembros de la clase base Constructores de clases derivadas Destructores de clases derivadas Punteros a objetos de una clase derivada Funciones virtuales Destructores virtuales Constructores virtuales Clases abstractas y funciones virtuales puras Herencia mltiple Herencia virtual Bibliografa ( para este tema ): 2 Francisco Javier Ceballos. Programacin orientada a objetos con C++, 2da Edicin, Editorial Rama. Pgs. 109-147.
Clase base
Clase base
Clase que tiene uno o ms hijos (clases derivadas) Herencia Permite la reutilizacin de cdigo entre clases Ejemplo: la clase CFicha pReferencia pTitulo
CFicha CFichaLibro
pAutor pEditorial NroVolumen
CFichaRevista
NroRevista anyo
CFichaVolumen
Clase derivada
Clase derivada Tipo definido por el usuario que tiene la propiedad de heredar los datos y funciones miembro de una o ms clases, denominadas clases base Sintaxis: class CDerivada : [{private/protected/public}] CBase1 [, [{private/protected/public}] CBase2] { //cuerpo de la clase derivada }; Derivacin simple Se da cuando una clase es derivada de una sola clase base Derivacin mltiple Se da cuando una clase es derivada de dos o ms clases base 4 Tipos de derivaciones private, protected y public
Tipos de derivaciones
Tipo de derivacin Miembros Clase Base Miembros Clase Derivada
private
protected
public
Ojo!! Los miembros privados de la clase base son inaccesibles en la clase derivada en todos los tipos de derivaciones
5
Herencia simple
Se da cuando una clase derivada lo es directamente de una sola clase base Por defecto, la derivacin es private Ejemplo: la clase CFichaLibro class CFichaLibro : public CFicha { private: char *pAutor; char *pEditorial; public: CFichaLibro(char *=0, char *=0, char *=0, char *=0); // 6 };
Es posible definir una funcin miembro en una clase base y despus redefinirla en la clase derivada void CFicha::VisualizarFicha() { cout<< pReferencia <<\t\t<< pTitulo << endl; } Redefinicin: void CFichaLibro::VisualizarFicha() { CFicha::VisualizarFicha(); cout<< pAutor <<,\t<< pEditorial << endl; }
Los constructores de la clase base no son heredados Creacin de un objeto de una clase derivada: Const. Derivada Const. Base Const. Derivada Notacin (Const. con argumentos): CDerivada::CDerivada(int a, char *b, char *c, float d) : CBase1(a, b), CBase2(c) Segn esto, los constructores de CFichaLibro quedan as: CFichaLibro::CFichaLibro(char *pref, char *ptit, char *paut, char *pedit) : Cficha(pref, ptit) {} CFichaLibro::CFichaLibro(const CFichaLibro &x) : CFicha (x) {}
8
El destructor de la clase base no es heredado Destruccin de un objeto de una clase derivada: Dest. Derivada Dest. Base
No requieren sintaxis especial Ejemplo: ~CFicha() {delete [] pReferencia; delete [] pTitulo; } ~CFichaLibro() {delete [] pAutor; delete [] pEditorial; }
Pueden ser declarados y manipulados de la misma forma CFichaLibro libro(1111,C++,Ceballos,RAMA); CFichaLibro *p = &libro; p->AsignarReferencia(2222); p->AsignarAutor(F.J. Ceballos);
Cuando accedemos a un objeto por medio de un puntero, el tipo del puntero determina qu funcin miembro puede ser llamada CFichaVolumen libro(1111,C++,Ceballos,Rama,2); CFichaLibro *p; p = &libro; p->AsignarReferencia(2222); p->AsignarAutor(F.J. Ceballos); p->AsignarNroDeVolumen(1); //error:no CFichaLibro
10
Funciones virtuales
Funcin virtual Funcin miembro de una clase base que puede ser redefinida en cada una de las clases derivadas y una vez redefinida puede ser accedida mediante un puntero a la clase base resolvindose la llamada en funcin del tipo del objeto apuntado Polimorfismo Facultad de llamar a una variedad de funciones usando el mismo medio de acceso
Ejemplo:
class Persona { public: Persona(char *n) { strcpy(nombre, n); } virtual void VerNombre() { cout<<nombre<<endl; } protected: char nombre[30]; }; class Empleado : public Persona { public: Empleado(char *n) : Persona(n) { } void VerNombre() { cout<<Emp: <<nombre<<endl; } } 12
13
Destructores virtuales
Si destruimos un objeto referenciado mediante un puntero a la clase base y el destructor no es virtual, estaremos llamando al destructor de la clase base Esto es un problema, ya que si el objeto es de una clase derivada, no se liberar la memoria de sus propios datos miembros punteros Por tanto, debemos respetar la regla siguiente: Si en una clase existen funciones virtuales, el destructor debe ser virtual
14
Constructores virtuales
Para lograr construir un objeto sin conocer a priori su tipo, la solucin consiste en definir una funcin que llame a un constructor y devuelva un objeto construido. Este objeto nuevo ser del mismo tipo del objeto apuntado por el puntero de la clase base. Si se quiere hacer una copia del objeto apuntado por un puntero de la clase base tendremos que implementar una funcin que llame al constructor copia del objeto apuntado. Ambos mtodos deben ser declarados virtuales en la clase base y redefinidos en las clases derivadas.
15
Clase que tiene al menos una funcin virtual pura. Se declara poniendo =0 despus de la declaracin de la funcin
No se pueden declarar objetos de una clase base abstracta Una funcin virtual pura de la clase base no se define La definicin se hace en las clases derivadas Ojo!!! Si no se define en la derivada se convierte en abstracta Todo esto es una cuestin de estilo
18
Ejemplo:
class Persona { public: Persona(char *n) { strcpy(nombre, n); } virtual void Mostrar() = 0; protected: char nombre[30]; }; class Empleado : public Persona { public: Empleado(char *n) : Persona(n) { } void Mostrar() { cout<<Emp: <<nombre<<endl; } }
19
Herencia mltiple
C++ permite crear clases derivadas a partir de varias clases base Los objetos de las clases derivadas heredarn los datos y funciones de todas las clases base. Sintaxis:
<clase_derivada>(<lista_de_parmetros>) : <clase_base1>(<lista_de_parmetros>) [,<clase_base2>(<lista_de_parmetros>)] {}
Problema: Qu sucede si en ms de una clase base existe una funcin con el mismo nombre? Ambiguedad. Ejemplo:
#include<iostream.h> class ClaseA { public: ClaseA() : valorA(10) { } int LeerValor() const { return valorA; } protected: int valorA; };
20
Si los constructores de las clases base reciben parmetros, estos debern ser llamados desde el constructor de la derivada:
class ClaseC : public ClaseA, public ClaseB { public: 22 ClaseC(int va, int vb) : ClaseA (va), ClaseB (vb) { }
Herencia virtual
Algunas veces puede suceder que una clase derivada herede dos veces los mismos datos y funciones de una clase base:
ClaseA ClaseA
ClaseB
ClaseC
ClaseD
23
Con esto logramos que la ClaseD herede una vez los datos y funciones de la ClaseA. La estructura queda as:
ClaseA
ClaseB
ClaseC
ClaseD
24
Herencia virtual
El constructor de la ClaseA deber ser invocado desde el de la ClaseD, ya que ni la ClaseB ni la ClaseC lo harn automticamente: ClaseA (int va) : valorA(va) { } ... ClaseB (int va, int vb) : ClaseA(va), valorB(vb) { } ... ClaseC (int va, int vc) : ClaseA(va), valorC(vc) { } ... ClaseD (int va, int vb, int vc, int vd) : ClaseA(va), ClaseB(va,vb), ClaseC(va,vc), valorD(vd) { }
Si observamos el constructor de la ClaseD veremos que es necesario usar el constructor de la ClaseA, a pesar de que el valor 25 del dato valorA se pasa como parmetro tanto a la ClaseB como a la ClaseC.