Vimos en el concepto anterior que dos clases pueden estar
relacionadas por la colaboración. Ahora veremos otro tipo de relaciones
entre clases que es la Herencia.
La herencia significa que se pueden crear nuevas clases partiendo de clases existentes, que tendrá todas los ,
propiedades y los métodos de su 'superclase' o 'clase padre' y además
se le podrán añadir otros atributos, propiedades y métodos propios.
clase padre
Clase de la que desciende o deriva una clase. Las clases hijas
(descendientes) heredan (incorporan) automáticamente los atributos,
propiedades y métodos de la la clase padre.
Subclase
Clase desciendiente de otra. Hereda automáticamente los atributos,
propiedades y métodos de su superclase. Es una especialización de otra
clase. Admiten la definición de nuevos atributos 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
FordK Renault 9
Siempre hacia abajo en la jerarquía hay una especialización (las subclases añaden nuevos atributos, propiedades y métodos.
2) Imaginemos la clase . Qué clases podrían derivar de ella?
Software
DeAplicacion DeBase
ProcesadorTexto PlanillaDeCalculo SistemaOperativo
Word WordPerfect Excel Lotus123 Linux Windows
El primer tipo de relación que habíamos visto clases, es la de colaboración. Recordemos que es cuando una clase contiene un objeto de otra clase como atributo.
Cuando la relación entre dos clases es del tipo "...tiene un..." o
"...es parte de...", no debemos implementar herencia. Estamos frente a
una relación de colaboración de clases no de herencia.
Si tenemos una ClaseA y otra ClaseB y notamos que entre ellas existe
una relacion de tipo "... tiene un...", no debe implementarse herencia
sino declarar en la clase ClaseA un atributo de la clase ClaseB.
Por ejemplo: tenemos una clase Auto, una clase Rueda y una clase
Volante. Vemos que la relación entre ellas es: Auto "...tiene 4..."
Rueda, Volante "...es parte de..." Auto; pero la clase Auto no debe
derivar de Rueda ni Volante de Auto porque la relación no es de
tipo-subtipo sino de colaboración. Debemos declarar en la clase Auto 4
atributos de tipo Rueda y 1 de tipo Volante.
Luego si vemos que dos clase 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
Problema 1:
Ahora plantearemos el primer problema utilizando herencia. Supongamos
que necesitamos implementar dos clases que llamaremos Suma y Resta.
Cada clase tiene como atributo valor1, valor2 y resultado. Las
propiedades a definir son Valor1, Valor2 y Resultado, el método Operar
(que en el caso de la clase "Suma" suma los dos y en el caso de la clase "Resta" hace la diferencia entre Valor1 y Valor2.
Si analizamos ambas clases encontramos que muchas propiedades son
idénticos. En estos casos es bueno definir una clase padre que agrupe
dichas propiedades, atributos y responsabilidades comunes.
La relación de herencia que podemos disponer para este problema es:
Operacion
Suma Resta
Solamente el método operar es distinto clases Suma y Resta (esto hace
que no lo podamos disponer en la clase Operacion), luego las propiedades
Valor1, Valor2 son idénticos a las dos clases, esto hace que podamos
disponerlos en la clase Operacion. Lo mismo las propiedades Valor1,
Valor2 y Resultado se definirán en la clase padre Operacion.
Crear un proyecto y luego crear cuatro clases llamadas: Operacion, Suma, Resta y Prueba
Programa:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Herencia1
{
public class Operacion {
protected int valor1;
protected int valor2;
protected int resultado;
public int Valor1
{
set
{
valor1=value;
}
get
{
return valor1;
}
}
public int Valor2
{
set
{
valor2=value;
}
get
{
return valor2;
}
}
public int Resultado
{
protected set
{
resultado=value;
}
get
{
return resultado;
}
}
}
public class Suma: Operacion
{
public void Operar()
{
Resultado=Valor1+Valor2;
}
}
public class Resta: Operacion
{
public void Operar()
{
Resultado=Valor1-Valor2;
}
}
class Prueba
{
static void Main(string[] args)
{
Suma suma1 = new Suma();
suma1.Valor1 = 10;
suma1.Valor2 = 7;
suma1.Operar();
Console.WriteLine("La suma de " + suma1.Valor1 + " y " +
suma1.Valor2 + " es " + suma1.Resultado);
Resta resta1 = new Resta();
resta1.Valor1 = 8;
resta1.Valor2 = 4;
resta1.Operar();
Console.WriteLine("La diferencia de " + resta1.Valor1 +
" y " + resta1.Valor2 + " es " + resta1.Resultado);
Console.ReadKey();
}
}
}
La clase Operación define tres atributos y sus tres propiedades que las acceden:
protected int valor1;
protected int valor2;
protected int resultado;
public int Valor1
{
set
{
valor1=value;
}
get
{
return valor1;
}
}
public int Valor2
{
set
{
valor2=value;
}
get
{
return valor2;
}
}
public int Resultado
{
protected set
{
resultado=value;
}
get
{
return resultado;
}
}
Ya veremos que definimos los atributos con este nuevo modificador de
acceso (protected) para que la subclase tenga acceso a dichos atributos.
Si los definimos private las subclases no pueden acceder a dichos
atributos.
Ahora veamos como es la sintaxis para indicar que una clase hereda de otra:
public class Suma: Operacion
Disponemos dos puntos y seguidamente el nombre de la clase padre (con
esto estamos indicando que todas las propiedades de la clase Operación
son también propiedades de la clase Suma.
Luego la característica que añade la clase Suma es el siguiente método:
public void Operar()
{
Resultado=Valor1+Valor2;
}
El método Operar puede acceder a las propiedades heredadas (siempre y
cuando los mismos se declaren protected, en caso que sean private si
bien lo hereda de la clase padre solo los pueden modificar métodos de
dicha clase padre)
Ahora podemos decir que la clase Suma tiene tres propiedades y un método.
Luego en otra clase creamos un objeto de la clase Suma:
class Prueba
{
static void Main(string[] args)
{
Suma suma1 = new Suma();
suma1.Valor1 = 10;
suma1.Valor2 = 7;
suma1.Operar();
Console.WriteLine("La suma de " + suma1.Valor1 + " y " +
suma1.Valor2 + " es " + suma1.Resultado);
Resta resta1 = new Resta();
resta1.Valor1 = 8;
resta1.Valor2 = 4;
resta1.Operar();
Console.WriteLine("La diferencia de " + resta1.Valor1 +
" y " + resta1.Valor2 + " es " + resta1.Resultado);
Console.ReadKey();
}
}
Podemos llamar tanto al método propio de la clase Suma "Operar()"
como acceder a las propiedades heredadas de la clase Operacion. Quien
utilice la clase Suma solo debe conocer que métodos y propiedades
públicas tiene (independientemente que pertenezcan a la clase Suma o a
una clase superior)
La lógica es similar para declarar la clase Resta.
La clase Operación agrupa en este caso un conjunto de atributos y
propiedades comunes a un conjunto de subclases (Suma, Resta). No tiene
sentido definir objetos de la clase Operacion.
El planteo de jerarquías de clases es una tarea compleja que requiere
un perfecto entendimiento de todas las clases que intervienen en un
problema, cuales son sus atributos, propiedades y responsabilidades.
Problema 2:
Confeccionar una clase Persona que tenga como atributos el nombre y
la edad (definir las propiedades para poder acceder a dichos atributos).
Definir como responsabilidad un método para imprimir.
Plantear una segunda clase Empleado que herede de la clase Persona.
Añadir un atributo sueldo ( y su propiedad) y el método para imprimir su
sueldo.
Definir un objeto de la clase Persona y llamar a sus métodos y
propiedades. También crear un objeto de la clase Empleado y llamar a sus
métodos y propiedades.
Programa:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Herencia2
{
public class Persona
{
protected string nombre;
protected int edad;
public string Nombre
{
set
{
nombre = value;
}
get
{
return nombre;
}
}
public int Edad
{
set
{
edad = value;
}
get
{
return edad;
}
}
public void Imprimir()
{
Console.WriteLine("Nombre:" + Nombre);
Console.WriteLine("Edad:" + Edad);
}
}
public class Empleado : Persona
{
protected float sueldo;
public float Sueldo
{
set
{
sueldo = value;
}
get
{
return sueldo;
}
}
new public void Imprimir()
{
base.Imprimir();
Console.WriteLine("Sueldo:" + Sueldo);
}
}
class Prueba
{
static void Main(string[] args)
{
Persona persona1 = new Persona();
persona1.Nombre = "Juan";
persona1.Edad = 25;
Console.WriteLine("Los datos de la persona son:");
persona1.Imprimir();
Empleado empleado1 = new Empleado();
empleado1.Nombre = "Ana";
empleado1.Edad=42;
empleado1.Sueldo = 2524;
Console.WriteLine("Los dats del empleado son:");
empleado1.Imprimir();
Console.ReadKey();
}
}
}
La clase Persona define los atributos protegidos (protected) nombre y
edad. Luego las propiedades públicas Nombre y Edad (que acceden a los
atributos para modificarlos o consultar sus valores.
El método imprimir es público para que se lo pueda llamar desde donde definimos un objeto de esta clase.
public class Persona
{
protected string nombre;
protected int edad;
public string Nombre
{
set
{
nombre = value;
}
get
{
return nombre;
}
}
public int Edad
{
set
{
edad = value;
}
get
{
return edad;
}
}
public void Imprimir()
{
Console.WriteLine("Nombre:" + Nombre);
Console.WriteLine("Edad:" + Edad);
}
}
La clase Empleado hereda de la clase Persona y agrega un atributo
llamado sueldo y la respectiva propiedad Sueldo para acceder al
atributo. Como la clase Empleado define otro método Imprimir debemos
anteceder la palabla clave new (con esto indicamos que sobreescribimos
el método existente en la clase padre.
Para llamar desde el método imprimir de la clase Empleado al método
imprimir de la clase Persona es con la sintaxis base.Imprimir()
public class Empleado : Persona
{
protected float sueldo;
public float Sueldo
{
set
{
sueldo = value;
}
get
{
return sueldo;
}
}
new public void Imprimir()
{
base.Imprimir();
Console.WriteLine("Sueldo:" + Sueldo);
}
}
Por último en la clase Prueba creamos un objeto de la clase Persona y un objeto de la clase Empleado:
class Prueba
{
static void Main(string[] args)
{
Persona persona1 = new Persona();
persona1.Nombre = "Juan";
persona1.Edad = 25;
Console.WriteLine("Los datos de la persona son:");
persona1.Imprimir();
Empleado empleado1 = new Empleado();
empleado1.Nombre = "Ana";
empleado1.Edad=42;
empleado1.Sueldo = 2524;
Console.WriteLine("Los dats del empleado son:");
empleado1.Imprimir();
Console.ReadKey();
}
}