Héritage et interfaces
Ce que tu vas apprendre
- Créer une classe qui hérite d'une autre et redéfinir une méthode.
- Faire appel au comportement de la classe de base avec
base. - Décrire un contrat avec une interface et l'implémenter dans plusieurs classes.
L'idée de l'héritage
Sur ton site de recettes, un dessert et un plat ont des points communs : un nom, un temps de préparation. Plutôt que de tout écrire deux fois, une classe peut hériter d'une autre. Elle reçoit alors ses membres et peut en ajouter.
La classe d'origine s'appelle la classe de base. La classe qui hérite s'appelle la classe dérivée.
public class Recette
{
public string Nom { get; }
public Recette(string nom)
{
Nom = nom;
}
public virtual string Decrire() => $"Recette : {Nom}";
}
public class Dessert : Recette
{
public Dessert(string nom) : base(nom) { }
}
Dessert : Recette se lit « Dessert hérite de Recette ». Un Dessert possède la propriété Nom et la méthode Decrire sans les réécrire.
Le constructeur de Dessert appelle : base(nom) pour passer le nom au constructeur de la classe de base.
Redéfinir avec virtual et override
Un dessert veut se décrire autrement. La classe de base marque la méthode virtual (elle peut être redéfinie), et la classe dérivée utilise override :
public class Dessert : Recette
{
public int Sucre { get; }
public Dessert(string nom, int sucre) : base(nom)
{
Sucre = sucre;
}
public override string Decrire() => $"Dessert : {Nom}, {Sucre} g de sucre";
}
Le résultat dépend du type réel de l'objet :
Recette r = new Recette("Soupe");
Recette d = new Dessert("Tarte", 80);
Console.WriteLine(r.Decrire()); // Recette : Soupe
Console.WriteLine(d.Decrire()); // Dessert : Tarte, 80 g de sucre
La variable d a le type Recette, mais l'objet est un Dessert. C'est la version du Dessert qui s'exécute. On appelle cela le polymorphisme : un même appel, des comportements différents selon l'objet.
Réutiliser le parent avec base
Dans une méthode redéfinie, base.Methode() appelle la version de la classe de base :
public override string Decrire() => base.Decrire() + $" (dessert, {Sucre} g de sucre)";
Tu complètes ainsi le comportement au lieu de le remplacer.
Classe abstraite
Parfois, la classe de base n'a pas de sens seule : une « recette » générique n'existe pas dans la cuisine. Marque-la abstract pour interdire de la créer directement :
public abstract class Recette
{
public abstract int Minutes();
}
public class Crepes : Recette
{
public override int Minutes() => 30;
}
Une méthode abstract n'a pas de corps. Chaque classe dérivée doit l'écrire avec override. Le mot-clé sealed fait l'inverse : il interdit à une classe d'être héritée.
Les interfaces
Une interface est un contrat : elle liste des membres qu'une classe doit fournir, sans écrire leur code. Par convention, son nom commence par un I.
public interface IPrix
{
double CalculerPrix();
}
public class Crepes : IPrix
{
public double CalculerPrix() => 3.5;
}
public class Menu : IPrix
{
public double CalculerPrix() => 12.0;
}
Crepes : IPrix signifie que Crepes promet de fournir CalculerPrix. Si elle l'oublie, le compilateur refuse le programme.
Une classe peut implémenter plusieurs interfaces, en les séparant par des virgules. Ces deux classes n'ont aucun lien d'héritage, mais on peut les traiter ensemble :
var elements = new List<IPrix> { new Crepes(), new Menu() };
foreach (IPrix element in elements)
{
Console.WriteLine(element.CalculerPrix());
}
Héritage ou interface
| Critère | Héritage | Interface |
|---|---|---|
| Code partagé | Oui, la classe de base le contient | Non, seulement la liste des membres |
| Nombre autorisé | Une seule classe de base | Autant que nécessaire |
| Relation | « est un » (un Dessert est une Recette) | « sait faire » (peut donner un prix) |
À retenir
class B : Afait hériter B de A ;: base(...)appelle le constructeur de la classe de base.virtualautorise la redéfinition,overrideredéfinit,base.appelle la version du parent.- Une classe
abstractne peut pas être créée seule ;sealedinterdit l'héritage. - Une interface est un contrat sans code (
IPrix) qu'une classe implémente, et une classe peut en implémenter plusieurs. - Hérite pour partager du code entre classes proches, utilise une interface pour un comportement commun à des classes sans lien.
Pour aller plus loin
Sources officielles
Ensuite
Classes, propriétés et records
Modéliser une recette avec une classe, ses propriétés et son constructeur, puis découvrir les records pour des données simples comparables par valeur.
LINQ et async/await
Filtrer, trier et calculer sur des collections avec LINQ, puis écrire du code asynchrone avec Task, async et await.
- Projet
- Lignes de code
- Niveau
- Le quartier
- Appartement
- C#
- Pièce
- 5/7
- Plan n°
- csharp/05.heritage-et-interfaces