Introducción a C#
Por Nacho Cabanes, versión 0.93 de 16-abr-2010


(Nota: Estás viendo una versión del curso antigua, creada en 2009. Es recomendable que sigas la versión 2015, mucho más actualizada, con contenidos más detallados, más ejemplos y más ejercicios propuestos)

6.3. La herencia. Visibilidad

Vamos a ver ahora cómo definir una nueva clase de objetos a partir de otra ya existente. Por ejemplo, vamos a crear una clase "Porton" a partir de la clase "Puerta". Un portón tendrá las mismas características que una puerta (ancho, alto, color, abierto o no), pero además se podrá bloquear, lo que supondrá un nuevo atributo y nuevos métodos para bloquear y desbloquear:

 
public class Porton: Puerta
{
 
  bool bloqueada;  
 
  public void Bloquear() 
  {
    bloqueada = true;
  }
 
  public void Desbloquear() 
  {
    bloqueada = false;
  }
 

Con "public class Porton: Puerta" indicamos que Porton debe "heredar" todo lo que ya habíamos definido para Puerta. Por eso, no hace falta indicar nuevamente que un Portón tendrá un cierto ancho, o un color, o que se puede abrir: todo eso lo tiene por ser un "descendiente" de Puerta.

No tenemos por qué heredar todo; también podemos "redefinir" algo que ya existía. Por ejemplo, nos puede interesar que "MostrarEstado" ahora nos diga también si la puerta está bloqueada. Para eso, basta con volverlo a declarar y añadir la palabra "new" para indicar al compilador de C# que sabemos que ya existe ese método y que sabemos seguro que lo queremos redefinir:

 
  public new void MostrarEstado() 
  {
    Console.WriteLine("Ancho: {0}", ancho);
    Console.WriteLine("Alto: {0}", alto);
    Console.WriteLine("Color: {0}", color);
    Console.WriteLine("Abierta: {0}", abierta);
    Console.WriteLine("Bloqueada: {0}", bloqueada);
  }
 

Aun así, esto todavía no funciona: los atributos de una Puerta, como el "ancho" y el "alto" estaban declarados como "privados" (es lo que se considera si no decimos los contrario), por lo que no son accesibles desde ninguna otra clase, ni siquiera desde Porton.

La solución más razonable no es declararlos como "public", porque no queremos que sean accesibles desde cualquier sitio. Sólo querríamos que esos datos estuvieran disponibles para todos los tipos de Puerta, incluyendo sus "descendientes", como un Porton. Esto se puede conseguir usando otro método de acceso: "protected". Todo lo que declaremos como "protected" será accesible por las clases derivadas de la actual, pero por nadie más:

 
public class Puerta
{
 
  protected int ancho;     // Ancho en centimetros
  protected int alto;      // Alto en centimetros
  protected int color;     // Color en formato RGB
  protected bool abierta;  // Abierta o cerrada
 
  public void Abrir() 
  ...
 

(Si quisiéramos dejar claro que algún elemento de una clase debe ser totalmente privado, podemos usar la palabra "private", en vez de "public" o "protected").

Un fuente completo que declarase la clase Puerta, la clase Porton a partir de ella, y que además contuviese un pequeño "Main" de prueba podría ser:

/*---------------------------*/
/*  Ejemplo en C# nº 60:     */
/*  ejemplo60.cs             */
/*                           */
/*  Segundo ejemplo de       */ 
/*  clases: herencia         */
/*                           */
/*  Introduccion a C#,       */
/*    Nacho Cabanes          */
/*---------------------------*/
 
using System;
 
// -------------------------------
public class Puerta
{
 
  protected int ancho;     // Ancho en centimetros
  protected int alto;      // Alto en centimetros
  protected int color;     // Color en formato RGB
  protected bool abierta;  // Abierta o cerrada
 
  public void Abrir() 
  {
    abierta = true;
  }
 
  public void Cerrar() 
  {
    abierta = false;
  }
 
  public void MostrarEstado() 
  {
    Console.WriteLine("Ancho: {0}", ancho);
    Console.WriteLine("Alto: {0}", alto);
    Console.WriteLine("Color: {0}", color);
    Console.WriteLine("Abierta: {0}", abierta);
  }
 
} // Final de la clase Puerta   
 
 
// -------------------------------
public class Porton: Puerta
{
 
  bool bloqueada;  
 
  public void Bloquear() 
  {
    bloqueada = true;
  }
 
  public void Desbloquear() 
  {
    bloqueada = false;
  }
 
  public new void MostrarEstado() 
  {
    Console.WriteLine("Ancho: {0}", ancho);
    Console.WriteLine("Alto: {0}", alto);
    Console.WriteLine("Color: {0}", color);
    Console.WriteLine("Abierta: {0}", abierta);
    Console.WriteLine("Bloqueada: {0}", bloqueada);
  }
 
} // Final de la clase Porton
 
// -------------------------------
public class Ejemplo60
{
 
  public static void Main()
  {
    Porton p = new Porton();
 
    Console.WriteLine("Valores iniciales...");
    p.MostrarEstado();
 
    Console.WriteLine("\nVamos a bloquear y a abrir...");
    p.Bloquear();
    p.MostrarEstado();
 
    Console.WriteLine("\nVamos a desbloquear y a abrir...");
    p.Abrir();
    p.Desbloquear();
    p.MostrarEstado();
  }
 
}