Ya hemos visto que es posible
definir tipos cuyos métodos se hereden
de definiciones de otros tipos. Lo que ahora vamos a ver es que además es
posible cambiar dichar definición en la clase hija, para lo que habría que
haber precedido con la palabra reservada virtual la definición de dicho método en la clase
padre. A este tipo de métodos se les llama métodos
virtuales, y la sintaxis que se usa para definirlos es la siguiente:
virtual
<tipoDevuelto> <nombreMétodo>(<parámetros>)
{
<código>
}
Si en alguna clase hija
quisiésemos dar una nueva definición del <código> del método, simplemente lo
volveríamos a definir en la misma pero sustituyendo en su definición la palabra
reservada virtual
por override.
Es decir, usaríamos esta sintaxis:
override
<tipoDevuelto> <nombreMétodo>(<parámetros>)
{
<nuevoCódigo>
}
Nótese que esta posibilidad de
cambiar el código de un método en su clase hija sólo se da si en la clase padre
el método fue definido como virtual. En caso contrario,
el compilador considerará un error intentar redefinirlo.
El lenguaje C# impone la
restricción de que toda redefinición de método que queramos realizar incorpore
la partícula override para forzar a que el programador esté
seguro de que verdaderamente lo que quiere hacer es cambiar el significado de
un método heredado. Así se evita que por accidente defina un método del que ya
exista una definición en una clase padre. Además, C# no permite definir un
método como override
y virtual
a la vez, ya que ello tendría un significado absurdo: estaríamos dando una
redefinición de un método que vamos a definir.
Por otro lado, cuando definamos
un método como override ha de cumplirse que en alguna clase
antecesora (su clase padre, su clase abuela, etc.) de la clase en la que se ha
realizado la definición del mismo exista un método virtual con el mismo nombre
que el redefinido. Si no, el compilador informará de error por intento de
redefinición de método no existente o no virtual. Así se evita que por
accidente un programador crea que está redefiniendo un método del que no exista
definición previa o que redefina un método que el creador de la clase base no
desee que se pueda redefinir.
Para aclarar mejor el concepto de
método virtual, vamos a mostrar un ejemplo en el que cambiaremos la definición
del método Cumpleaños() en los
objetos Persona por una nueva
versión en la que se muestre un mensaje cada vez que se ejecute, y
redefiniremos dicha nueva versión para los objetos Trabajador
de modo que el mensaje mostrado sea otro. El código de este ejemplo es el que
se muestra a continuación:
using System;
class Persona
{
public string Nombre; // Campo de cada objeto Persona que
almacena su nombre
public int Edad; // Campo de cada objeto Persona que almacena su edad
public string NIF; // Campo de cada objeto Persona
que almacena su NIF
public virtual void Cumpleaños() //
Incrementa en uno de la edad del objeto Persona
{
Console.WriteLine(“Incrementada
edad de persona”);
}
public Persona (string nombre, int edad,
string nif) // Constructor de Persona
{
Nombre = nombre;
Edad = edad;
NIF = nif;
}
}
class
Trabajador: Persona
{
public int Sueldo; // Campo de cada objeto
Trabajador que almacena cuánto gana
Trabajador(string nombre, int edad, string
nif, int sueldo): base(nombre, edad, nif)
{ // Inicializamos cada Trabajador en base al
constructor de Persona
Sueldo = sueldo;
}
public override Cumpleaños()
{
Edad++;
Console.WriteLine(“Incrementada
edad de persona”);
}
public static void Main()
{
Persona p = new
Persona("Carlos", 22, "77588261-Z", 100000);
Trabajador
t = new Trabajador("Josan", 22, "77588260-Z", 100000);
t.Cumpleaños();
p.Cumpleaños();
}
}
Nótese cómo se ha añadido el
modificador virtual
en la definición de Cumpleaños()
en la clase Persona para
habilitar la posibilidad de que dicho método puede ser redefinido en clase
hijas de Persona y cómo
se ha añado override
en la redefinición del mismo dentro de la clase Trabajador para
indicar que la nueva definición del método es una redefinición del heredado de
la clase. La salida de este programa confirma que la implementación de Cumpleaños()
es distinta en cada clase, pues es de la forma:
Incrementada edad
de trabajador
Incrementada edad
de persona
También es importante señalar que
para que la redefinición sea válida ha sido necesario añadir la partícula public
a la definición del método original, pues si no se incluyese se consideraría
que el método sólo es accesible desde dentro de la clase donde se ha definido,
lo que no tiene sentido en métodos virtuales ya que entonces nunca podría ser redefinido. De hecho, si se
excluyese el modificador public el compilador
informaría de un error ante este absurdo. Además, este modificador también se
ha mantenido en la redefinición de Cumpleaños()
porque toda redefinición de un método virtual ha de mantener los mismos
modificadores de acceso que el método original para ser válida.