virtual, override y new
Comencemos hablando de perritos, o de Canis lupus familiaris para ser más exactos.
Toma, por ejemplo, la clase CanisLupusFamiliaris
(perro doméstico), que tiene dos métodos, nota que uno está marcado como virtual
y otro no.
public class CanisLupusFamiliaris // Perro doméstico
{
public virtual void Ladrar()
{
Console.WriteLine("Ladrido genéico");
}
public void MoverOrejas()
{
Console.WriteLine("Error: sin información");
}
}
Y una clase derivada, llamada Chihuahua
, que como sabrás, es un perro doméstico. El Chihuahua, al ser algo más específico tiene su propia manera de ladrar y mover las orejas, define sus propios métodos:
public class Chihuahua : CanisLupusFamiliaris
{
public void Ladrar()
{
Console.WriteLine("Bau, bau");
}
public void MoverOrejas()
{
Console.WriteLine("Mueve sus orejas peludas");
}
}
new
, override
Sin embargo, el Chihuahua
no es el único perro, también tenemos un GranDanes
, que nuevamente, es un perro doméstico y hereda de CanisLupusFamiliaris
. Pero, a diferencia de la clase anterior, esta implementa su forma de ladrar y de mover la cola de manera distinta:
public class GranDanes : CanisLupusFamiliaris
{
public override void Ladrar()
{
Console.WriteLine("Woof, woof");
}
public new void MoverOrejas()
{
Console.WriteLine("Mueve sus orejas gigantezcas");
}
}
Si te das cuenta, aparecieron dos palabras en la definición de los métodos: new
y override
La explicación de estas palabras es la siguiente:
override
El modificador override
se usa para indicar que el método que se está definiendo modificará el comportamiento del definido en la clase base. Para que un miembro pueda ser sobrescrito debe estar marcado con el modificador virtual
. La clase GranDanes
está sobrescribiendo el método virtual Ladrar
. Entonces no importa desde donde llamemos a este método, siempre llamaremos a la implementación de esta clase.
Si compilas el código anterior aparecerán unas advertencias en tu IDE, indicándote que en la clase Chihuahua
el método Ladrar
esconde al método del mismo nombre en la clase CanisLupusFamiliaris
, sin embargo, al estar marcado como virtual también nos da la opción de marcarlo con override
:
Como la clase GranDanes
sí está sobrescribiendo el archivo, estas advertencias no aparecen.
new
En este ámbito (antes de la definición de un método o propiedad de una clase) nos ayuda a especificar que la definición de nuestro método está ocultando una definición similar en la clase padre. En el caso de GranDanes
, el método MoverOrejas
está escondiendo la definición de la clase padre. En realidad la palabra new
no es más que una indicación para el compilador de que estás conciente de que estás escondiendo una definición ya existente, no tiene otro efecto en tu programa.
Si compilas el código anterior aparecerán unas advertencias en tu IDE, indicándote que en la clase Chihuahua
el método MoverOrejas
esconde al método del mismo nombre en la clase CanisLupusFamiliaris
:
Esta advertencia no aparece en la clase GranDanes
.
Ejemplo:
Considera el siguiente programa, en donde declaramos un perro de la clase base y llamamos a sus métodos, nada raro, todo funciona como debería funcionar:
// En pantalla: Canis genérico: Ladrido genérico Error: sin información
En el siguiente bloque creamos un Chihuahua
pero lo asignamos a un objeto de la clase base, después, al llamar a los métodos, vemos que en realidad está llamando a los métodos de la clase base, puesto que no está sobrescribiéndolos con override
:
// En pantalla: Chihuahua (Canis): Ladrido genérico Error: sin información
En el siguiente bloque creamos un Chihuahua
, ahora si asignándolo a un objeto de su misma clase, la llamada a los métodos nos da el resultado esperado:
// En pantalla: Chihuahua: guau, guau Mueve sus orejitas
En el siguiente bloque creamos un GranDanes
, asignándolo a un objeto de la clase base, la llamada a los métodos nos da resultados mixtos, Ladrar
accede a la implementación de GranDanes
porque sobrescribimos el método, pero MoverOrejas
accede al de la clase base:
// En pantalla: Gran danes (Canis): WOOF! WOOF! Error: sin información
En el siguiente bloque creamos un GranDanes
, asignándolo a una clase de su tipo, las llamadas a los métodos se hacen directamente a este tipo:
// En pantalla: Gran danes: WOOF! WOOF! Mueve sus orejas gigantezcas
Para terminar
Como vimos, las palabras virtual
y override
están completamente relacionadas y nos ayudan a preservar el comportamiento definido en las subclases de un tipo cuando se hace referencia a ellos desde el tipo base. Por otro lado, new
no es más que un indicador para que el compilador no piense que estamos cometiendo un error si nombramos un miembro de una clase como uno de los que contenga su clase base.
Por cierto, en este ejemplo solamente utilicé métodos, pero las tres palabras de las que hablé en este post aplican para cualquier miembro: campos, propiedades, métodos, eventos, operadores, indizadores y constructores.