La herencia significa que se pueden crear nuevas clases partiendo de clases existentes, que tendrá todos los campos y los métodos de su 'superclase' o 'clase padre' y además se le podrán añadir otros campos y métodos propios.
Clase de la que desciende o deriva una clase. Las clases hijas (descendientes) heredan (incorporan) automáticamente las propiedades y métodos de la la clase padre.
Clase descendiente de otra. Hereda automáticamente los campos y métodos de su superclase. Es una especialización de otra clase.
Admiten la definición de nuevos campos y métodos para aumentar la especialización de la clase.
Veamos algunos ejemplos teóricos de herencia:
1) Imaginemos la clase Vehículo. Qué clases podrían derivar de ella?
Vehiculo
Colectivo Moto Auto
FordK Renault Fluence
Siempre hacia abajo en la jerarquía hay una especialización (las subclases añaden nuevos campos y métodos)
2) Imaginemos la clase Software. ¿Qué clases podrían derivar de ella?
Software
DeAplicacion DeBase
ProcesadorTexto PlanillaDeCalculo SistemaOperativo
Word WordPerfect Excel Lotus123 Linux Windows
Si vemos que dos clases responden a la pregunta ClaseA "..es un.." ClaseB es posible que haya una relación de herencia.
Por ejemplo:
Auto "es un" Vehiculo Circulo "es una" Figura Mouse "es un" DispositivoEntrada Suma "es una" Operacion
Plantear una clase Persona que contenga dos campos: nombre y edad. Definir como responsabilidades la carga, impresión y mostrar si es mayor de edad.
En el bloque principal del programa definir un objeto de la clase Persona y llamar a sus métodos.
Declarar una segunda clase llamada Empleado que herede de la clase Persona y agregue un campo sueldo y muestre si debe pagar impuestos (sueldo superior a 3000)
También en la clase empleado permitir cargar los datos e imprimir.
En el bloque principal también definir un objeto de la clase Empleado y llamar a sus métodos.
program Proyecto132;
{$APPTYPE CONSOLE}
type
TPersona = class
Nombre: String;
Edad: Integer;
procedure Cargar;
procedure Imprimir;
procedure EsMayorDeEdad;
end;
TEmpleado = class(TPersona)
Sueldo: Double;
procedure Cargar;
procedure Imprimir;
procedure PagaImpuestos;
end;
procedure TPersona.Cargar;
begin
Write('Ingrese el nombre:');
ReadLn(Nombre);
Write('Ingrese la edad:');
ReadLn(Edad);
end;
procedure TPersona.Imprimir;
begin
WriteLn('Nombre:', Nombre);
WriteLn('Edad:', Edad);
end;
procedure TPersona.EsMayorDeEdad;
begin
if Edad >= 18 then
WriteLn('Es mayor de edad')
else
WriteLn('No es mayor de edad');
end;
procedure TEmpleado.Cargar;
begin
inherited Cargar;
Write('Ingrese el sueldo:');
ReadLn(Sueldo);
end;
procedure TEmpleado.Imprimir;
begin
inherited Imprimir;
WriteLn('Sueldo:', Sueldo:0:2)
end;
procedure TEmpleado.PagaImpuestos;
begin
if Sueldo > 3000 then
WriteLn('El empleado ', Nombre, ' debe pagar impuestos')
else
WriteLn('El empleado ', Nombre, ' no debe pagar impuestos')
end;
var
Persona1: TPersona;
Empleado1: TEmpleado;
begin
Persona1 := TPersona.Create;
WriteLn('Datos de la persona');
Persona1.Cargar;
Persona1.Imprimir;
Persona1.EsMayorDeEdad;
Persona1.Free;
Empleado1 := TEmpleado.Create;
WriteLn('Datos del empleado');
Empleado1.Cargar;
Empleado1.Imprimir;
Empleado1.EsMayorDeEdad;
Empleado1.PagaImpuestos;
Empleado1.Free;
ReadLn;
end.
La declaración TPersona no sufre cambios con respecto al ejercicio que desarrollamos conceptos anteriores:
TPersona = class
Nombre: String;
Edad: Integer;
procedure Cargar;
procedure Imprimir;
procedure EsMayorDeEdad;
end;
Lo mismo la implementación de los métodos de la clase TPersona no presentan cambios:
procedure TPersona.Cargar;
begin
Write('Ingrese el nombre:');
ReadLn(Nombre);
Write('Ingrese la edad:');
ReadLn(Edad);
end;
procedure TPersona.Imprimir;
begin
WriteLn('Nombre:', Nombre);
WriteLn('Edad:', Edad);
end;
procedure TPersona.EsMayorDeEdad;
begin
if Edad >= 18 then
WriteLn('Es mayor de edad')
else
WriteLn('No es mayor de edad');
end;
Lo nuevo se presenta cuando declaramos la clase TEmpleado indicando que la misma hereda de la clase TPersona:
TEmpleado = class(TPersona)
Entre paréntesis luego de la palabra clave class indicamos el nombre de la clase que heredamos.
Es importante decir que la declaración de la clase TPersona debe estar obligatoriamente antes de la declaración de la clase TEmpleado, sino se produce un error sintáctico.
Con indicar que la clase TEmpleado hereda de TPersona significa que la clase TEmpleado ya tiene dos campos (Nombre y Edad) y tres métodos (Cargar, Imprimir y EsMayorDeEdad)
La clase TEmpleado define el campo Sueldo y tres métodos:
Sueldo: Double;
procedure Cargar;
procedure Imprimir;
procedure PagaImpuestos;
El método Cargar tendrá por objetivo cargar los datos del empleado (Nombre, Edad y Sueldo):
procedure TEmpleado.Cargar;
begin
inherited Cargar;
Write('Ingrese el sueldo:');
ReadLn(Sueldo);
end;
Dentro del método cargar y con las ventajas que nos proporciona la herencia, mediante la palabra clave inherided llamamos al método Cargar de la clase padre (donde se carga el nombre y la edad) y luego solicitamos el ingreso del Sueldo.
La herencia nos permite reducir línea de código evitando tener que escribir:
procedure TEmpleado.Cargar;
begin
Write('Ingrese el nombre:');
ReadLn(Nombre);
Write('Ingrese la edad:');
ReadLn(Edad);
Write('Ingrese el sueldo:');
ReadLn(Sueldo);
end;
De forma similar cuando codificamos el método Imprimir de la clase TEmpleado llamamos al método Imprimir de la clase padre:
procedure TEmpleado.Imprimir;
begin
inherited Imprimir;
WriteLn('Sueldo:', Sueldo:0:2)
end;
El tercer método tiene por objetivo mostrar si paga impuestos el empleado:
procedure TEmpleado.PagaImpuestos;
begin
if Sueldo > 3000 then
WriteLn('El empleado ', Nombre, ' debe pagar impuestos')
else
WriteLn('El empleado ', Nombre, ' no debe pagar impuestos')
end;
Es importante notar que podemos acceder al campo Nombre, que si bien no está definido en la clase TEmpleado si lo está en la clase TPersona.
Definimos dos variables globales, uno de tipo TPersona y otra de tipo TEmpleado:
var Persona1: TPersona; Empleado1: TEmpleado;
Creamos el objeto Persona1 y llamamos a sus métodos:
begin
Persona1 := TPersona.Create;
WriteLn('Datos de la persona');
Persona1.Cargar;
Persona1.Imprimir;
Persona1.EsMayorDeEdad;
Persona1.Free;
Luego creamos el objeto Empleado1 y también llamamos a sus métodos:
Empleado1 := TEmpleado.Create;
WriteLn('Datos del empleado');
Empleado1.Cargar;
Empleado1.Imprimir;
Empleado1.EsMayorDeEdad;
Empleado1.PagaImpuestos;
Empleado1.Free;
ReadLn;
end.
Es importante notar que podemos llamar al método EsMayorDeEdad desde el objeto Empleado1 gracias a que este objeto hereda de la clase TPersona.
Ahora ya podemos decir de donde salen los métodos Create y Free, son métodos heredados de la clase TObject.
Toda clase hereda directamente o indirectamente de la clase TObject. Podemos modificar el programa y utilizar la sintaxis:
TPersona = class(TObject)
Es decir que toda clase si no indicamos que hereda de otra luego está heredando de la clase TObject que define los métodos Create y Free.
Gracias a esta herencia podemos escribir:
Persona1 := TPersona.Create; ... Persona1.Free;
Lo mismo sucede con la clase TEmpleado al heredar de la clase TPersona y esta heredar de la clase TObject podemos codificar:
Empleado1 := TEmpleado.Create; ... Empleado1.Free;
Declarar una clase llamada TCalculadora que disponga de dos métodos para la carga de valores de tipo Double (almacenar los datos en dos campos)
Definir las responsabilidades de sumar, restar, multiplicar, dividir e imprimir.
Declarar luego una clase llamada TCalculadoraCientifica que herede de TCalculadora y añada las responsabilidades de calcular el cuadrado del primer número y la raíz cuadrada.
program Proyecto133;
{$APPTYPE CONSOLE}
type
TCalculadora = class
Valor1: Double;
Valor2: Double;
Resultado: Double;
procedure Cargar1;
procedure Cargar2;
procedure Sumar;
procedure Restar;
procedure Multiplicar;
procedure Dividir;
procedure Imprimir;
end;
TCalculadoraCientifica = class(TCalculadora)
procedure Cuadrado;
procedure Raiz;
end;
procedure TCalculadora.Cargar1;
begin
Write('Ingrese valor:');
ReadLn(Valor1);
end;
procedure TCalculadora.Cargar2;
begin
Write('Ingrese valor:');
ReadLn(Valor2);
end;
procedure TCalculadora.Sumar;
begin
Resultado := Valor1 + Valor2;
end;
procedure TCalculadora.Restar;
begin
Resultado := Valor1 - Valor2
end;
procedure TCalculadora.Multiplicar;
begin
Resultado := Valor1 * Valor2;
end;
procedure TCalculadora.Dividir;
begin
Resultado := Valor1 / Valor2;
end;
procedure TCalculadora.Imprimir;
begin
WriteLn('Resultado:', Resultado:0:2);
end;
procedure TCalculadoraCientifica.Cuadrado;
begin
Resultado := Valor1 * Valor1;
end;
procedure TCalculadoraCientifica.Raiz;
begin
Resultado := Sqrt(Valor1);
end;
var
Calculadora1: TCalculadora;
CalculadoraCientifica1: TCalculadoraCientifica;
begin
WriteLn('Uso de la calculadora');
Calculadora1 := TCalculadora.Create;
Calculadora1.Cargar1;
Calculadora1.Cargar2;
Calculadora1.Sumar;
Calculadora1.Imprimir;
Calculadora1.Restar;
Calculadora1.Imprimir;
Calculadora1.Multiplicar;
Calculadora1.Imprimir;
Calculadora1.Dividir;
Calculadora1.Imprimir;
Calculadora1.Free;
WriteLn('Uso de la calculadora científica');
CalculadoraCientifica1 := TCalculadoraCientifica.Create;
CalculadoraCientifica1.Cargar1;
CalculadoraCientifica1.Cargar2;
CalculadoraCientifica1.Sumar;
CalculadoraCientifica1.Imprimir;
CalculadoraCientifica1.Restar;
CalculadoraCientifica1.Imprimir;
CalculadoraCientifica1.Multiplicar;
CalculadoraCientifica1.Imprimir;
CalculadoraCientifica1.Dividir;
CalculadoraCientifica1.Imprimir;
CalculadoraCientifica1.Cuadrado;
CalculadoraCientifica1.Imprimir;
CalculadoraCientifica1.Raiz;
CalculadoraCientifica1.Imprimir;
CalculadoraCientifica1.Free;
ReadLn;
end.
La clase TCalculadora hereda por defecto de la clase TObject, que por lo general no se escribe:
TCalculadora = class
Valor1: Double;
Valor2: Double;
Resultado: Double;
procedure Cargar1;
procedure Cargar2;
procedure Sumar;
procedure Restar;
procedure Multiplicar;
procedure Dividir;
procedure Imprimir;
end;
Definimos 3 campos y 7 métodos, más abajo codificamos los 7 métodos.
La clase TCalculadoraCientifica hereda de la clase TCalculadora y añade dos responsabilidades que permita calcular el cuadrado y la raiz cuadrada de un número:
TCalculadoraCientifica = class(TCalculadora)
procedure Cuadrado;
procedure Raiz;
end;
Tengamos en cuenta que con la herencia la clase TCalculadoraCientifica es una calculadora común, es decir que podemos sumar, restar, multiplicar y dividir, pero añade los métodos de cálculo del cuadrado y la raíz.
Valor := Random(6) + 1;Imprimir el valor del dado.
program Proyecto134;
{$APPTYPE CONSOLE}
type
TDado = class
Valor: Integer;
procedure Tirar;
procedure Imprimir;
end;
TDadoRecuadro = class(TDado)
procedure Imprimir;
end;
procedure TDado.Tirar;
begin
Valor := Random(6) + 1;
end;
procedure TDado.Imprimir;
begin
WriteLn(Valor);
end;
procedure TDadoRecuadro.Imprimir;
begin
WriteLn('***');
WriteLn('*', Valor, '*');
WriteLn('***');
end;
var
Dado1: TDado;
DadoRecuadro1: TDadoRecuadro;
begin
Randomize; //Generamos una semilla de valores aleatorios distinta para cada ejecución del programa
WriteLn('Prueba del dado común');
Dado1 := TDado.Create;
Dado1.Tirar;
Dado1.Imprimir;
Dado1.Free;
WriteLn('Prueba del dado con recuadro');
DadoRecuadro1 := TDadoRecuadro.Create;
DadoRecuadro1.Tirar;
DadoRecuadro1.Imprimir;
DadoRecuadro1.Free;
ReadLn;
end.