Está en la página 1de 21

Herencia

Seccin 7.1-7.2

Tipos de datos encapsulados


Recordemos que: Un ADT con: Tipo con conjunto de valores Conjunto de operaciones con firmas Representacin estructura de componentes de tipos de datos Solo el nombre del tipo y las operaciones son visibles fuera del objeto definido. Ejemplo: RegEstudiante es tipo Externamente visible: void PonerNombre(RegEstudiante, Nombre) nombre ObtenerNombre(RegEstudiante) Interno al modulo: char Nombre[20]; float Promedio; char Direccin[50]; TipoCurso Calendario[10];
2

Implementacin de la encapsulacin
Implementacin Usual en Ada: package NumeroRacional is type racional is record -- Tipo definido por el usuario num, den: integer end record; procedure mult(x in racional; -- Operacin abstracta y in racional; z out racional); end package; package body NumeroRacional is -- Encapsulacin procedure mult(x in racional; y in racional; z out racional) begin z.num := x.num * y.num; z.den := x.den * y.den; end; end package;
3

Uso de datos encapsulados


Uso usual del encapsulado NumeroRacional: Ejemplo: En el procedimiento principal hacer: var A, B, C: racional; A.num := 7; Debe ser ilegal A.den := 1; Mult(A, B, C);

No existe obligacin de encapsulacin


Cualquier procedimiento tiene acceso a componentes de tipo. Se puede manipular A.num y A.den sin usar los procedimientos del paquete NumeroRacional. Miremos el modelo alternativo para obligar el uso de encapsulacin.
4

Tipos privados
package NumeroRacional is type racional is private; -- Tipo definido por el usuario procedure mult(x in racional; -- Operacin abstracta y in racional; z out racional); private type racional is record -- Tipo definido por el usuario num, den: integer end record; end package; package body NumeroRacional is Como lo anterior procedure mult(x in racional; y in racional; z out racional) begin z.num := x.num * y.num; z.den := x.den * y.den; end; end package;
5

Tipo privado y proteccin


Pero ahora: var A: racional; A.num := 7; -- ahora es ilegal. Private bloquea el uso de num y y fuera del paquete NumeroRacional. Cual es el rol de private? Cualquier declaracin en la parte private no es visible fuera de package Cual es la diferencia en semntica de racional? Cual es la diferencia en la implementacin de racional? Esta solucin encapsula y esconde los detalles de implementacin de racional.
6

Ejemplo en C++ de NumeroRacional


C++ crea objetos de clases definidas por el usuario. Almacenamiento de datos Conjunto de operaciones Tipo racional puede ser especificado en class racional{ public: void mult( racional x; racional { num = x.num * y.num; den = x.den * y.den;} protected: int num; int den } racional A, B, C; A.mult(B,C) invoca funcin A.num = B.num * C.num Ilegal. No hay C++ como: y)

encapsulada acceso a num y den

Almacenamiento para clases de C++

Visibilidad de objetos: public: conocido globalmente private: conocido solo localmente protected provisto por herencia

Herencia
Herencia provee mecanismos para pasar informacin de un objeto de datos a otro automticamente Provee una forma de mbito de datos similar al mbito esttico.

Herencia a travs de Datos en lenguajes orientado a objetos es explicito a travs de tipos derivados.

mbito esttico (arriba) Nombres son conocidos implcitamente a travs de nombres de procedimientos anidados

Clases derivadas en C++


Considere la clase racional en C++ discutida anteriormente: class complejo: racional { public: void mult( complejo x; complejo y); { ptreal.mult(x.ptreal,y.ptreal)ptreal.mult(x.ptimag,y.ptimag) ... void inicial(complejo x) {x.ptreal.num = 0; x.ptreal.den = 1 } // complejo hereda componente racional. private: racional ptreal; racional ptimag } . . . complejo M, N, P; M.mult(N,P)

10

Potencia de la herencia
class racional { public: mult( ...) { ... } protected: error( ...) { ... } ... private: ... } class complejo:racional { public: mult( ...) { ... } private: ... } complejo X; Funcin de error es pasada (heredada) a clase complejo, por lo que X.error es una llamada de funcin vlida. Cualquier clase derivada puede invocar error y una funcin legal ser ejecutada. Pero que sucede si queremos que error imprima el tipo de su argumento? (por Ej., queremos conocer si el error ocurri en un dato racional o complejo?)

11

Potencia de la herencia (continuacin)


La herencia es normalmente una propiedad esttica: Funcin error en clase complejo es conocida por el compilador que est en la clase racional. x.error compilador conoce donde esta la funcin error. Como puede racional::error conocer de donde fue llamado, como racional::error o complejo::error?

Una manera - Usar el argumento de la funcin: error('racional') o error('complejo')


Alternativa: Uso de funciones virtuales

12

Funciones virtuales
Clase base: class racional { error() { cout << nombre() << endl; } string nombre() { return racional;} ... } Clase derivada: class complejo: racional { string nombre() { return complejo;} ... } Pero si el error es llamado, racional es siempre impreso ya que la llamada racional::nombre esta compilada en clase racional para la llamada en la funcin error. Pero si nombre es definido como: virtual string nombre() { return racional;} Entonces nombre() esta definida como una funcin virtual y la funcin nombre en el objeto actual es invocada cuando nombre() es llamada en racional::error.

13

Implementacin de funciones virtuales


Las funciones virtuales implican un descriptor en tiempo de corrida con una localizacin de objeto

racional A; complejo B; A.error() error llamar a nombre() en racional B.error() error llamar a nombre() en complejo

14

Atributos adicionales de herencia en C++


Problema: Se quiere acceder los datos de la clase objeto. Esto es, en racional::error, imprime valores para num y den de cada componente de la clase objeto Puede usar funciones adicionales virtuales punteros this : *this.contador

Accesa objeto contador en objeto actual pasado a error.


A.error(string X) es compilado como: racional::error(&A, X) Esto es, pasa clase objeto A y tambin cadena X.

16

Clases amigas
Clases amigas: Herencia estricta algunas veces es difcil de realizar (por Ej., Muy difcil de hacerlo bien por lo que hay que buscar alternativas!)

class cosa { ... MiFcn(complejo A) { ... A.ptreal }


Pero, A.ptreal es dato privado Elabore la solucin aadiendo: friend class cosa en clase complejo Permite que cosa acceda a componentes escondidos y evite la estricta herencia jerrquica de C++ Estudios han demostrado que esta es la caracterstica mas propensa a error de C++; en vez de eso, redisee la jerarqua de clases.

17

Herencia mixta
Asuma que queremos aadir la caracterstica X y B: a ambas clases A

La manera usual es la de redefinir ambas clases. Herencia mixta: Tiene definicin que es sumada a clase base (No es parte de C++) Por ejemplo, lo siguiente es una sintaxis posible: featureX mixin {int valcounter} Aade campo a objeto nuevaclaseA class A mod featureX; nuevaclaseB class B mod featureX; Se puede obtener un efecto similar con herencia mltiple: class nuevaclaseA:A,featureX { ... } class nuevaclaseB:B,featureX { ... }
18

Principios de herencia
1. Especializacin: Forma usual de herencia: Cheque hereda propiedad de Cuenta. Opuesto es generalizacin: Cuenta es ms general Que Cheque. 2. Descomposicin: Rompe un objeto encapsulado en partes. Un objeto racional es un num y un den. Concepto opuesto es acumulacin (aggregation). 3. Instanciacin: Creacin de instancias de un objeto: racional A, B, C; Representa 3 instancias de objeto racional. 4. Individualizacin: Relacionado con especializacin. Separa objetos por funciones y no estructura. Una pila y un conjunto pueden ambos ser un puntero a un arreglo y un puntero ndice, pero son funcionalmente diferentes. Lo opuesto es agrupacin (grouping.)
19

Sobrecarga
Dos operadores con el mismo nombre pero diferente firmas se dice que tienen sobrecarga. Lenguajes antiguos permitieron sobrecarga en funciones incorporadas, por Ej., real+real es diferente de integer+integer es diferente de integer+real es diferente de real+integer Sobrecarga en C++; cout << 123 el operador << tiene argumentos cout y 123. cout << ``abc'' el operador << tiene argumentos cout y ``abc''.

20

Sobrecarga (continuacin)
Sobrecarga no-primitiva: mifuncin (int a, int b) { ... } mifuncin (int a) { ... } Cada firma difiere, por lo que una funcin diferente es llamada. Note que esto es una propiedad esttica determinada por el compilador. Que hay sobre lo siguiente: mifuncin (int a, int b=7) { ... } mifuncin (char a) { ... }

mifuncin(3)? mifuncin('a')?

21

Resolucin de sobrecarga
En C++: Dado X(args) {...} Dado X(args) {...} 1. Si las firmas corresponden exactamente, la segunda es una redeclaracin de la primera. 2. Si los argumentos corresponden exactamente pero, el tipo de retorno no corresponde, el segundo es un error. 3. Si los argumentos no corresponden exactamente, la segunda es una definicin de sobrecarga. Conceptos relacionados: Coercin: A menudo implementadas como parte de los operadores con sobrecarga incorporados (discutido anteriormente) Polimorfismo: Los tipos estn definidos por argumentos parametrizados (por Ej., type micadena = string(N: integer);) proc mifuncin(X: micadena(N)) {...} call mifuncin(Midato(17)); Discutiremos polimorfismo ms adelante.
22

También podría gustarte