herencia

10
Escuela Superior de Ingenieros de San Sebastián Escuela Superior de Ingenieros de San Sebastián - Tecn Tecnun un 1 Herencia y Herencia y Polimorfismo en C++ Polimorfismo en C++ Informática II Informática II Fundamentos de Programación Fundamentos de Programación Escuela Superior de Ingenieros de San Sebastián Escuela Superior de Ingenieros de San Sebastián - Tecn Tecnun un 2 Herencia Herencia Concepto de " Concepto de " herencia herencia ": ": Una clase -clase derivada- puede definirse a partir de otra clase ya existente (clase base), de la que hereda sus variables y funciones miembro. La clase derivada puede añadir y/o redefinir nuevas variables y/o funciones miembro. La clase base suele ser más general que la clase derivada. Ésta añade nuevas determinaciones o especificaciones (nuevas variables y/o funciones miembro). A su vez, la clase derivada puede ser clase base de una nueva clase derivada, que hereda sus variables y funciones miembro. Se puede constituir una jerarquía de clases. Además de Además de public public y y private private , C++ permite también definir miembros , C++ permite también definir miembros protected protected. Los miembros protected, al igual que los private, no son accesibles desde fuera de la clase. En una clase base, los miembros protected se diferencian de los private en que sí pueden ser accesibles para las clases derivadas de dicha clase base. Para la Para la clase derivada clase derivada , la , la clase base clase base se se puede heredar como puede heredar como pública pública o como o como privada privada: La clase derivada no tiene acceso a los miembros private de la clase base. Sí tiene acceso a los miembros public y protected. Si la clase base se hereda como public, la clase derivada hereda los miembros public y protected de la clase base como miembros public y protected, respectivamente. Si la clase base se hereda como private, la clase derivada hereda todos los miembros de la clase base como private.

Upload: francisco-ayala

Post on 16-Dec-2015

4 views

Category:

Documents


2 download

DESCRIPTION

Herencia

TRANSCRIPT

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 1

    Herencia y Herencia y Polimorfismo en C++Polimorfismo en C++

    Informtica IIInformtica IIFundamentos de ProgramacinFundamentos de Programacin

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 2

    HerenciaHerencia Concepto de "Concepto de "herenciaherencia":":

    Una clase -clase derivada- puede definirse a partir de otra clase ya existente (clase base), de la que hereda sus variables y funciones miembro.

    La clase derivada puede aadir y/o redefinir nuevas variables y/o funciones miembro. La clase base suele ser ms general que la clase derivada. sta aade nuevas determinaciones

    o especificaciones (nuevas variables y/o funciones miembro). A su vez, la clase derivada puede ser clase base de una nueva clase derivada, que hereda sus

    variables y funciones miembro. Se puede constituir una jerarqua de clases. Adems de Adems de publicpublic y y privateprivate, C++ permite tambin definir miembros , C++ permite tambin definir miembros protectedprotected..

    Los miembros protected, al igual que los private, no son accesibles desde fuera de la clase. En una clase base, los miembros protected se diferencian de los private en que s pueden ser

    accesibles para las clases derivadas de dicha clase base. Para la Para la clase derivadaclase derivada, la , la clase base clase base sese puede heredar como puede heredar como pblicapblica o como o como privadaprivada::

    La clase derivada no tiene acceso a los miembros private de la clase base. S tiene acceso a los miembros public y protected.

    Si la clase base se hereda como public, la clase derivada hereda los miembros public y protected de la clase base como miembros public y protected, respectivamente.

    Si la clase base se hereda como private, la clase derivada hereda todos los miembros de la clase base como private.

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 3

    Ej. de herencia: clase "empleado"Ej. de herencia: clase "empleado" Supngase que un departamento de una empresa utiliza tres tipos de

    empleados: subcontratado: cobra por horas. vendedor: cobra por horas, ms una comisin de las ventas. encargado: cobra una cantidad fija por mes.

    y que se desea hacer una funcin llamada calcular_pago() que calcule lo que hay que pagar cada mes a cada empleado.

    Se puede pensar en una jerarqua de empleados de la forma indicada en la figura:

    Los principios de esta jerarqua son los siguientes: Todos son empleados. Los vendedores cobran por horas como los subcontratados (de hecho son un tipo

    especial de subcontratados), pero tienen adems una comisin, por lo que pueden ser considerados como una particularizacin de stos.

    Los encargados slo tienen en comn con los dems el hecho de ser empleados.

    Empleado

    Subcontratado Encargado

    Vendedor

    Enc_ventas

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 4

    Ej. de herencia (Ej. de herencia (contcont.).)Clase base Clase base empleadoempleado::

    class empleado{private:

    char nombre[31];public:

    empleado();empleado(const char *nom);char *devolver_nombre();float calcular_pago() {return 0.0;}

    };Clase derivada Clase derivada subcontratadosubcontratado::

    class subcontratado : public empleado{private:

    float tarifa;float no_horas;

    public:subcontratado(const char *nom);void fijar_tarifa(float tar);void contar_horas(float horas);float calcular_pago();

    };Obsrvese la forma en que, en cada clase derivada, se define la forma en que se hereda la clase base como public o private.

    Clase derivada Clase derivada vendedorvendedor::class vendedor : public subcontratado{

    private:float comision;float ventas_realizadas;

    public:vendedor(const char *nom);void fijar_comision(float com);void contar_ventas(float ventas);float calcular_pago();

    };

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 5

    Ej. de herencia (Ej. de herencia (contcont.).)Definicin de la clase derivada encargado:

    class encargado : public empleado{private:

    float sueldo_mensual;public:

    encargado(const char *nom);void fijar_sueldo(float sueldo);float calcular_pago();

    };

    Recurdese que cada una de las clase derivadas hereda todos los miembros de la clase base correspondiente.

    La clase vendedor hereda los miembros de las clases subcontratado y empleado.

    La clase derivada no puede acceder directamente a las variables miembro privadas de la clase base: hay que utilizar las funciones pblicas de la clase base.

    Una clase derivada puede redefinir (definir una funcin diferente con el mismo nombre) alguna de las funciones miembro de la clase base.

    La funcin de la clase base es accesible en la clase derivada por medio del operador (::). La funcin redefinida es utilizable directamente en la clase derivada.

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 6

    Ej. de herencia (Ej. de herencia (contcont.).) Definicin de la funcin calcular_pago() en cada una de las clases:

    float subcontratado::calcular_pago() {return tarifa * no_horas;

    };

    float vendedor::calcular_pago() {return (subcontratado::calcular_pago() + comision * ventas_realizadas);

    };

    float encargado::calcular_pago() {return sueldo_mensual;

    };

    No sera correcto utilizar las definiciones:float vendedor::calcular_pago() {

    return (tarifa * no_horas + comision * ventas_realizadas);};

    float vendedor::calcular_pago() {return (calcular_pago() + comision * ventas_realizadas);

    };

    pues vendedor::calcular_pago() no tiene acceso a las variables privadas de subcontratado. La funcin calcular_pago() de vendedor no debe llamarse a s misma, sino a la de subcontratado.

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 7

    Constructores de clases derivadasConstructores de clases derivadas Un objeto de una clase derivada contiene todos los miembros de la clase base.

    El constructor de la clase derivada debe llamar al de la clase base. Cuando se define un constructor para una clase derivada, se debe especificar

    un inicializador base (llamada al constructor de la clase base). El inicializador base se especifica poniendo, a continuacin de los argumentos

    del constructor, el carcter (:) y un constructor de la clase base seguido de una lista de argumentos entre parntesis. Por ejemplo:

    // constructor para la clase subcontratadosubcontratado::subcontratado(const char *nom)

    : empleado(nom){

    tarifa = 0.0;no_horas = 0.0;

    };

    Al declarar un objeto de la clase derivada, se ejecuta primero el constructorde la clase base y luego el de la clase derivada.

    El inicializador base puede ser omitido si la clase base tiene un constructorpor defecto.

    El constructor de una clase derivada debe disponer de valores para sus propias variables y para el constructor de la clase base.

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 8

    Herencia mltiple. Herencia mltiple. Clases base virtualesClases base virtuales

    Una clase derivada puede heredar variables y funciones miembro de varias clases base. Por ejemplo, la clase encargado_ventas puede heredar los miembros de las clases encargado y

    vendedor. Se definira en la forma:class encargado_ventas : public encargado, public vendedor{

    ... // definicin de variables y funciones miembro};

    Una clase base no puede figurar directamente ms de una vez en la definicin de la clase derivada. Sin embargo, indirectamente una clase puede ser clase base ms de una vez de una clase derivada.

    Por ejemplo, la clase empleado es clase base por duplicado de la clase encargado_ventas. La clase encargado_ventas tiene por duplicado los miembros de la clase base empleado. Se puede utilizar el operador (::).

    Al llamar a la funcin devolver_nombre() dar error de ambigedad, ya que no sabe cual de las dos utilizar (por encargado o por vendedor).

    Para evitar esto, la clase base empleado debe ser declarada clase base virtual. En las definiciones de las clases derivadas hay que hacer:

    class subcontratado : public virtual empleado {...};class encargado : public virtual empleado {...};

    El constructor de la clase base virtual (empleado) siempre se llama antes que los constructores de las clases base no virtuales (encargado o subcontratado), por lo tanto en hay que llamar primero al constructor de empleado: vendedor(..,..,..) : empleado(..), subcontratado(...){ ; }

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 9

    Conversiones entre objetos de Conversiones entre objetos de clases base clases base y y clases derivadasclases derivadas

    Es posible realizar conversiones o asignaciones entre un objeto de una clase derivada a un objeto de la clase base (se puede ir de lo ms particular a lo ms general, aunque se pueda perder informacin). Es posible hacer:un_empleado = un_encargado;un_subcontratado = un_vendedor;

    No son posibles las conversiones en sentido contrario (de lo ms general a lo ms particular, pues no se dispone de valores para todas las variables miembro de la clase derivada y habra variables que quedaran sin inicializar).

    De forma anloga, se puede convertir un puntero a una clase derivada en un puntero a la clase base.

    Un puntero a la clase base puede almacenar la direccin de un objeto de cualquiera de las clases derivadas de esa clase base.

    Se puede hacer referencia a un objeto de una clase derivada con un puntero a la clase base.

    Cuando se hace referencia a un objeto por medio de un puntero, el tipo de puntero determina la funcin miembro que se aplica a dicho objeto, en el caso de que dicha funcin est definida en las clases base y derivada. .

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 10

    Punteros a la Punteros a la clase baseclase base para manejo para manejo de objetos de de objetos de clases derivadasclases derivadas

    En una jerarqua de clases con funciones del mismo nombre definidas en todas las clases, el tipo de objeto determina la funcin que se aplica.

    por ejemplo, con nombres de objetos:vendedor1.calcular_pago();operario3.calcular_pago();

    y con punteros a objetos:encargado *pntr1;pntr1->calcular_pago();

    A una funcin que espera un puntero a la clase base se le puede pasar un puntero a cualquiera de sus clases derivadas (por las leyes de conversin de punteros).

    De esta forma, una lista de objetos de distintas clases puede tratarse con la interface -con las funciones miembro- de la clase base.

    Este tratamiento es genrico, sin tener en cuenta las peculiaridades de las clases derivadas, pues si se utiliza un puntero a una clase base con un objeto de una clase derivada, se utiliza la funcin de la clase base.

    El tratamiento personalizado con punteros genricos (a objetos de la clase base) se consigue por medio del polimorfismo.

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 11

    Polimorfismo y funciones Polimorfismo y funciones virtualesvirtuales

    La palabra polimorfismo hace referencia a la capacidad de llamar a funciones miembro:

    con un nico nombre y anloga pero diferente misin, que acten sobre objetos distintos de una jerarqua de clases, que se llamen del modo preciso sin tener que especificar

    el tipo exacto de los objetos.

    for (i=0; icalcular_pago();

    La funcin calcular_pago() debe actuar correctamente con cada objeto de las clases derivadas de la clase Empleado, sin tener que pasar el tipo de objeto.

    Esto se hace: con punteros genricos a la clase base Empleado:

    Empleado *pempleado;cantidad = pempleado->calcular_pago();

    declarando calcular_pago() como funcin virtual en la clase base Empleado. si la funcin no se declara como virtual se utiliza siempre la funcin de la clase base

    Empleado::calcular_pago(). Si una clase no tiene definida una funcin, utiliza la heredada de la clase base.

    Oficial Tecnico

    Operario Directivo

    Empleado

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 12

    Polimorfismo y Polimorfismo y funciones virtuales (funciones virtuales (contcont.).)

    De ordinario, en C++ la llamada a una funcin determinada se establece en el momento de la compilacin (vinculacin esttica o temprana).

    Con funciones virtuales esto no es posible, pues no se sabe en ese momento a qu tipo de objeto apuntar el puntero en el instante de la llamada. La funcin a llamar se determina en tiempo de ejecucin (vinculacin dinmica o tarda).

    Con funciones virtuales es posible que un usuario aada nuevas clases a una jerarqua de clases, sin modificar o recompilar el cdigo original (por tanto, sin necesidad de conocer los ficheros fuentes).

    Las funciones virtuales son algo menos eficientes que las funciones normales: cada clase que utiliza funciones virtuales tiene un vector de punteros (uno por cada

    funcin virtual) llamado v-table. cada uno de estos punteros apunta a la funcin virtual que es apropiada para esa

    clase, en principio a la propia definicin si existe. si una clase no tiene su propia definicin de la funcin virtual, el puntero apunta a

    la funcin virtual de su clase base ms prxima que tenga una definicin propia. cada objeto contiene un puntero oculto a la v-table de su clase. Con el puntero al

    objeto se accede a la v-table de la clase y a travs de ella se accede a la definicin adecuada de la funcin virtual. ste es el trabajo extra.

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 13

    Funciones virtuales purasFunciones virtuales puras Una funcin virtual debe estar definida en la clase base de la jerarqua, aunque no se vaya a

    utilizar nunca: porque no existen objetos de esa clase, porque cada clase derivada tiene su propia definicin de esa funcin.

    Una funcin virtual de la clase base que no se va a utilizar nunca no necesita ser definida: basta declararla como funcin virtual pura.

    Una funcin virtual pura se declara en la forma:virtual float calcular_pago() const = 0; // virtual pura

    En este caso: no hace falta definir el cdigo de empleado::calcular_pago(). no se pueden definir objetos de la clase base empleado, pues las funciones virtuales

    puras no pueden ser llamadas. s se pueden definir punteros a la clase empleado, pues a travs de ellos pueden

    manejarse objetos de clases derivadas. Es necesario redefinir la funcin como const: float calcular_pago() const { ... }

    Clases abstractasClases abstractas:: A las clases que declaran funciones virtuales puras se les llama clases abstractas, pues

    no tienen objetos concretos de esa clase. Si una clase derivada no redefine una funcin virtual pura heredada, la clase derivada la

    hereda como funcin virtual pura y se convierte tambin en clase abstracta.

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 14

    FuncFunc. virtuales puras (. virtuales puras (contcont.).) Es habitual utilizar jerarquas de clases en las que las clases superiores son clases abstractas, que

    definen funciones virtuales puras que las clases concretas derivadas redefinen del modo adecuado. El constructor de la clase base se llama antes que el constructor de la clase derivada. Los destructores se llaman en orden opuesto a los constructores: primero el de la clase derivada y

    luego el de la clase base. Problema que puede presentarse:

    con reserva dinmica de memoria, si delete se aplica a un puntero de la clase base, se llama al destructor de la clase base, aunque dicho puntero apunte a un objeto de una clase derivada (se debera llamar primero al destructor de la clase derivada).

    la solucin es declarar el destructor de la clase base como virtual: virtual ~empleado(); esto hace que los destructores de las clases derivadas sean virtuales, aunque tengan nombres

    diferentes. as, si delete se aplica a un puntero de la clase base, el destructor adecuado se aplica segn el

    objeto de que se trate. si se define una clase con funciones virtuales, conviene definir un destructor virtual aunque la

    clase no lo necesite (puede haber clases derivadas que lo necesiten) No hay constructores virtuales.

    empleado *emp1 = new encargado("Carla",2500);delete emp1;

    Al eliminar el objeto con delete, slo se ejecutarel destructor de la clase base, si ste no es declaradocomo virtual.

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 15

    Ejemplo 1Ejemplo 1

    // Fichero Empleado.h// ejemplo de funciones virtuales#include

    class Empleado {public:

    virtual void imprime_cargo(){ cout

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 17

    Ejemplo 2Ejemplo 2// Fichero empleos.h#include

    class empleado {protected :

    char nombre[25];long salario;

    public:empleado(char*, long);virtual void display() {cout

  • Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 19

    Ejemplo 2 (Ejemplo 2 (contcont.).)// Fichero Empleos.cpp// funciones miembro de clases Directivo y Operario#include "empleos.h"#include #include

    // definicin de los constructoresempleado::empleado(char* name = "", long sueldo = 0)

    : salario(sueldo) {strcpy(nombre, name);

    }

    directivo::directivo(char* name = "", long sueldo = 0,char* title = "") : empleado(name, sueldo) {

    strcpy(titulo, title);}operario::operario(char* name = "", long sueldo = 0,

    char* job = "") : empleado(name, sueldo) {strcpy(puesto, job);

    }tecnico::tecnico(char* name = "", long sueldo = 0,

    char* job ="") : operario(name, sueldo, job){ ; }oficial::oficial(char* name = "", long sueldo = 0,

    char* job ="") : operario(name, sueldo, job){ ; }

    Oficial Tecnico

    Operario Directivo

    Empleado

    Escuela Superior de Ingenieros de San Sebastin Escuela Superior de Ingenieros de San Sebastin -- TecnTecnunun 20

    // fichero empresa.cpp// utilizacin de la clase empleos#include #include "empleos.h"void main(void){

    // punteros a objetos de distintas clasesdirectivo *m;operario *j;oficial *k;tecnico *i;

    // creacin de cuatro objetos de distintas clasesm = new directivo("Maria", 260000, "Ingeniera");j = new operario("Juan", 160000, "Soldador");k = new oficial("Koldo", 180000, "Teniente");i = new tecnico("Ignacio", 250000, "Ingeniero");

    // vector de punteros a la clase baseempleado *lista[8];// se guardan direcciones de objetos de// distintas claseslista[0] = m; lista[1] = j; lista[2] = k; lista[3] = i;lista[4] = new directivo("PEDRO", 2500000, "Economista");lista[5] = new operario("Leire", 25000, "Becaria");lista[6] = new oficial("Jon", 1500000, "Entrenador");lista[7] = new tecnico("Mario", 1600000, "Electricista");

    // Se tratan todos los objetos de las distintas clases de una forma unificadafor (int ii=0; iidisplay();cout