Mots-clés Virtual & Override
Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy — leçon 21 sur 70.
Lorsqu'une classe dérivée hérite d'une méthode, vous souhaitez parfois modifier complètement le comportement de cette méthode. Les mots-clés virtual et override travaillent ensemble pour rendre cela possible de manière contrôlée.
Marquez une méthode comme virtual dans la classe de base pour signaler que les classes dérivées sont autorisées à remplacer son implémentation :
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Some sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}Le mot-clé override dans la classe dérivée indique au compilateur que vous remplacez intentionnellement la méthode de base. Sans virtual sur la méthode de base, vous ne pouvez pas utiliser override.
La véritable puissance se manifeste lorsque vous utilisez une référence de classe de base pour contenir un objet dérivé :
Animal myPet = new Dog();
myPet.Speak(); // Sortie : Woof!Même si myPet est déclaré comme Animal, C# appelle la version Dog de Speak(). C'est ce qu'on appelle le polymorphisme d'exécution : la méthode réellement appelée dépend du type réel de l'objet, et non du type déclaré de la variable.
Vous pouvez toujours accéder à l'implémentation de base en utilisant base.Speak() à l'intérieur de votre redéfinition si vous souhaitez étendre plutôt que de remplacer complètement le comportement.
Défi
FacileConstruisons un système de notification qui démontre comment les classes dérivées peuvent remplacer complètement le comportement de la classe de base en utilisant les mots-clés virtual et override, tout en montrant la puissance du polymorphisme au moment de l'exécution.
Vous allez créer trois fichiers pour organiser votre code :
Notification.cs: Définissez une classeNotificationdans l'espace de nomsAlerts. Cette classe de base représente une notification générique avec une propriétéMessage(string) et un constructeur qui l'initialise. Incluez une méthodevirtualnomméeSend()qui retourne"Sending notification: {Message}".EmailNotification.cs: Définissez une classeEmailNotificationdans l'espace de nomsAlertsqui hérite deNotification. Ajoutez une propriétéRecipient(string) et un constructeur qui accepte à la fois le message et le destinataire (utilisezbasepour transmettre le message). Surchargez la méthodeSend()pour retourner"Emailing {Recipient}: {Message}".SmsNotification.cs: Définissez une classeSmsNotificationdans l'espace de nomsAlertsqui hérite également deNotification. Ajoutez une propriétéPhoneNumber(string) et un constructeur qui accepte à la fois le message et le numéro de téléphone. SurchargezSend()pour retourner"SMS to {PhoneNumber}: {Message}".Program.cs: Dans votre fichier principal, créez des instances des trois types de notification en utilisant les valeurs d'entrée. Démontrez ensuite le polymorphisme au moment de l'exécution en stockant les trois instances dans des variables de typeNotificationet en appelantSend()sur chacune d'elles.
Vous recevrez quatre entrées :
- Le message de notification
- L'adresse e-mail du destinataire
- Le numéro de téléphone pour le SMS
Affichez le résultat de l'appel à Send() sur chaque notification, stockée en tant que référence de la classe de base :
{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}Par exemple, si les entrées sont Meeting at 3pm, alice@email.com, et 555-1234, la sortie devrait être :
Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pmRemarquez comment, même si les trois sont stockées dans des variables de type Notification, chacune appelle sa propre version surchargée de Send(). C'est le polymorphisme au moment de l'exécution en action !
Aide-mémoire
Utilisez le mot-clé virtual dans une classe de base pour marquer une méthode que les classes dérivées peuvent remplacer :
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Some sound");
}
}Utilisez le mot-clé override dans une classe dérivée pour remplacer l'implémentation de la méthode de la classe de base :
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}Le polymorphisme à l'exécution se produit lorsqu'une référence de classe de base contient un objet dérivé - la méthode réellement appelée dépend du type réel de l'objet, et non du type déclaré de la variable :
Animal myPet = new Dog();
myPet.Speak(); // Sortie : Woof!Vous pouvez accéder à l'implémentation de base à l'intérieur d'une substitution en utilisant base :
public override void Speak()
{
base.Speak(); // Appelle la version de la classe de base
Console.WriteLine("Woof!");
}Essayez vous-même
using System;
using Alerts;
class Program
{
public static void Main(string[] args)
{
// Lire les entrées
string message = Console.ReadLine();
string email = Console.ReadLine();
string phone = Console.ReadLine();
// TODO: Créer des instances des trois types de notification
// Les stocker dans des variables Notification pour démontrer le polymorphisme
// TODO: Créer une Notification de base
Notification baseNotification;
// TODO: Créer une EmailNotification (stockée en tant que type Notification)
Notification emailNotification;
// TODO: Créer une SmsNotification (stockée en tant que type Notification)
Notification smsNotification;
// TODO: Appeler Send() sur chacune et afficher les résultats
// Les méthodes redéfinies seront appelées grâce au polymorphisme à l'exécution
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et Utilisateur