Palabras clave Virtual y Override
Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy. Lección 21 de 70.
Cuando una clase derivada hereda un método, a veces quieres cambiar por completo cómo se comporta ese método. Las palabras clave virtual y override trabajan juntas para hacerlo posible de forma controlada.
Marca un método como virtual en la clase base para indicar que las clases derivadas pueden reemplazar su implementación:
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Some sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}La palabra clave override en la clase derivada le indica al compilador que estás reemplazando intencionalmente el método de la clase base. Sin virtual en el método de la clase base, no puedes usar override.
El verdadero potencial se muestra cuando usas una referencia a la clase base para contener un objeto derivado:
Animal myPet = new Dog();
myPet.Speak(); // Salida: Woof!Aunque myPet se declara como Animal, C# llama a la versión de Dog de Speak(). Esto se llama polimorfismo en tiempo de ejecución: el método que se llama realmente depende del tipo real del objeto, no del tipo declarado de la variable.
Aún puedes acceder a la implementación base usando base.Speak() dentro de tu sobrescritura si quieres ampliar el comportamiento en lugar de reemplazarlo por completo.
Desafío
FácilVamos a crear un sistema de notificaciones que demuestra cómo las clases derivadas pueden sobrescribir por completo el comportamiento de la clase base mediante las palabras clave virtual y override, y también muestra el poder del polimorfismo en tiempo de ejecución.
Crearás tres archivos para organizar tu código:
Notification.cs: Define una claseNotificationen el espacio de nombresAlerts. Esta clase base representa una notificación genérica con una propiedadMessage(cadena) y un constructor que le asigna un valor. Incluye un métodovirtualllamadoSend()que devuelve"Sending notification: {Message}".EmailNotification.cs: Define una claseEmailNotificationen el espacio de nombresAlertsque hereda deNotification. Añade una propiedadRecipient(cadena) y un constructor que acepte tanto el mensaje como el destinatario (usabasepara pasar el mensaje). Sobrescribe el métodoSend()para que devuelva"Emailing {Recipient}: {Message}".SmsNotification.cs: Define una claseSmsNotificationen el espacio de nombresAlertsque también hereda deNotification. Añade una propiedadPhoneNumber(cadena) y un constructor que acepte tanto el mensaje como el número de teléfono. SobrescribeSend()para que devuelva"SMS to {PhoneNumber}: {Message}".Program.cs: En tu archivo principal, crea instancias de los tres tipos de notificación usando los valores de entrada. Después, demuestra el polimorfismo en tiempo de ejecución almacenando las tres en variables de tipoNotificationy llamando aSend()en cada una.
Recibirás cuatro entradas:
- El mensaje de la notificación
- La dirección de correo electrónico del destinatario
- El número de teléfono para SMS
Imprime el resultado de llamar a Send() en cada notificación, almacenada como una referencia a la clase base:
{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}Por ejemplo, si las entradas son Meeting at 3pm, alice@email.com y 555-1234, el resultado debería ser:
Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pmFíjate en que, aunque las tres están almacenadas en variables de tipo Notification, cada una llama a su propia versión sobrescrita de Send(). ¡Eso es el polimorfismo en tiempo de ejecución en acción!
Pruébalo tú mismo
using System;
using Alerts;
class Program
{
public static void Main(string[] args)
{
// Lee las entradas
string message = Console.ReadLine();
string email = Console.ReadLine();
string phone = Console.ReadLine();
// TODO: Crea instancias de los tres tipos de notificación
// Guárdalas en variables de tipo Notification para demostrar el polimorfismo
// TODO: Crea una Notification base
Notification baseNotification;
// TODO: Crea una EmailNotification (almacenada como tipo Notification)
Notification emailNotification;
// TODO: Crea una SmsNotification (almacenada como tipo Notification)
Notification smsNotification;
// TODO: Llama a Send() en cada una e imprime los resultados
// Los métodos sobrescritos se invocarán debido al polimorfismo en tiempo de ejecución
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosNamespaces y directivasIntro a clases y objetosLa palabra clave 'this'Métodos y parámetrosCampos vs PropiedadesConstructoresInicializadores de objetosResumen - Calculadora simple4Herencia
Sintaxis básica de herencia (:)La palabra clave 'base'Palabras clave Virtual y OverrideClases selladas (Sealed)La clase base 'object'Resumen: Jerarquía de empleados7Características avanzadas
Sobrecarga de operadoresIndexadores (this[])Sobrescritura de ToString()Métodos de extensiónResumen - Lista personalizada10Patrones de diseño - Parte 1
Introducción a los patrones de diseñoSingleton Thread-SafePatrón FactoryPatrón Observer (Eventos)Patrón Strategy2Propiedades y miembros estáticos
Propiedades autoimplementadasPropiedades de solo lectura y escrituraCampos y métodos estáticosClases estáticasMiembros con cuerpo de expresión5Polimorfismo e Interfaces
Polimorfismo: Compilación vs. EjecuciónInterfaz vs. Clase AbstractaInterfaces MúltiplesInterfaces ExplícitasUpcasting y DowncastingRepaso: Calculadora de Figuras8Conceptos avanzados de POO
Composición sobre herenciaGenéricos (clases y métodos)Delegados y eventosAtributos y ReflexiónIDisposable y la sentencia usingFundamentos de Inyección de dependencias11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Arquitectura de clases
Datos de instancia vs. estáticosPalabras clave 'readonly' y 'const'Campos de respaldoResumen - Gestor de cuentas bancarias6Encapsulamiento
Modificadores de accesoPropiedades para el encapsulamientoImplementación de ocultamiento de datosPatrones de inmutabilidadRepaso - Registros de estudiantesPractica por tu cuenta: Compilador de C# online