Está en la página 1de 25

PROGRAMACIN ORIENTADA A OBJETOS Clase 6: Clases derivadas

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

public protected private public protected private public protected private

private private Inaccesible protected protected Inaccesible public protected Inaccesible

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 };

Redefinir miembros de la clase base

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; }

De manera anloga, hay que definir el operador de asignacin 7 y el constructor copia

Constructores de clases derivadas


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

Destructores de clases derivadas


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; }

Punteros a objetos de una clase derivada

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

Sintaxis: virtual <tipo> <nombre_funcin>(<lista_parametros>)[{}];


11

Funciones virtuales (Ejemplo)

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

Funciones virtuales (Ejemplo)


class Estudiante : public Persona { public: Estudiante(char *n) : Persona(n) { } void VerNombre() { cout<<Est: <<nombre<<endl; } } void main() { Persona *Pepito = new Estudiante(Jose); Persona *Carlos = new Empleado(Carlos); Carlos->VerNombre(); Pepito->VerNombre(); delete Pepito; delete Carlos; }

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

Constructores virtuales - Ejemplo


class CPersona { ... virtual CPersona *nuevo() { return new CPersona; } virtual CPersona *clonar() { return new CPersona(*this); } ... }; class CEstudiante : public CPersona { ... CPersona *nuevo() { return new CEstudiante; } CPersona *clonar() { return new CEstudiante(*this); } ... };
16

Constructores virtuales - Ejemplo


CPersona p("Luis", "281-140502", 23, 'm'); CEstudiante e("Elena", "281-121075-0040X", 28, 'f', "c-1512570"); CPersona *p1 = &p; CPersona *p2 = &e; CPersona *p3 = p1->clonar(); CPersona *p4 = p2->clonar(); p3->Get(); p4->Get(); delete p3; delete p4; p3 = p1->nuevo(); p4 = p2->nuevo(); p3->Set(); p4->Set(); p3->Get(); 17 p4->Get(); delete p3; delete p4;

Clases abstractas y funciones virtuales puras

Clase abstracta Funcin virtual pura

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

Clases abstractas y funciones virtuales puras

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

Herencia mltiple (cont.)


class ClaseB { public: ClaseB() : valorB(20) { } int LeerValor() const { return valorB; } protected: int valorB; }; class ClaseC : public ClaseA, public ClaseB { }; void main() { ClaseC cc; cout << cc.LeerValor() << endl; // error: ambigedad cout << cc.ClaseA::LeerValor() << endl; } 21 Solucin: Llamar a la funcin con el nombre de la clase o redefinir la funcin en la clase derivada!!

Herencia mltiple (cont.)


class ClaseC : public ClaseA, public ClaseB { public: int LeerValor() const { return ClaseA::LeerValor(); } }; void main() { ClaseC cc; cout << cc.LeerValor() << endl; // Bien! }

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

Esto origina un problema de ambiguedad. Solucin: utilizar herencia virtual

23

Herencia virtual - Ejemplo


class ClaseB : virtual public ClaseA { }; class ClaseC : virtual public ClaseA { }; class ClaseD: public ClaseB, public ClaseC { };

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.

También podría gustarte