8. Héritage
L’héritage est l’un des concepts de base de la programmation orientée objet. L’héritage permet à une classe (appelée classe dérivée) d’hériter ds variables, de méthodes et des propriétés d’une autre (la classe de base), et d’étendre le concept de la classe de base et de le développer.
Revenant à l’exemple des voitures, nous pourrions avoir des classes dérivées des voitures comme les sous-classes : “voitures avec boîte de vitesses manuelle” et “voiture avec boîte de vitesses automatique”. Les deux sous-classes héritent de toutes les propriétés et comportements de base de la classe mais elles se spécialisent dans la façon de changer de vitesse.
Toutes les classes du Framework .NET héritent implicitement de la classe de base Object. En C#, la relation d’héritage entre les classes est exprimée en utilisant les deux points (:) qui sont équivalents à Inherits de VB.NET.
Reprenons une partie de la classe Personne que nous avons précédemment créée :
public class Personne { string mPrenom; protected string mNom; public Personne(string Prenom, string Nom) { mPrenom = Prenom; mNom = Nom; } public string Prenom { get { return mPrenom; } set { mPrenom = value; } } //... }
Nous observons que la variable mNom a été déclarée comme protected. Nous voulons maintenant définir un nouveau concept, celui d’Étudiant, c’est-à-dire une personne avec un numéro de matricule. Pour ce faire, l’étudiant doit hériter de Personne (vous pouvez également dire que l’étudiant étend la classe Personne) :
public class Etudiant : Personne { private int mMatricule; public Etudiant(string Prenom, string Nom, int Matricule) : base(Prenom, Nom) { mMatricule = Matricule; } public int Matricule { get { return mMatricule; } set { mMatricule = value; } } }
Après avoir défini cette relation, on peut utiliser dans la classe Étudiant tout ce qui a été défini comme public, protected ou private, qu’il s’agisse d’une variable, d’une routine ou d’une propriété.
Par exemple, dans Étudiant, nous pouvons utiliser la variable mNom, qui est définie comme protégée dans la classe Personne, alors que mPrenom n’est pas visible car le modificateur d’accès par défaut est private.
Examinons le fragment
: base(Prenom, Nom)
juste après le constructeur Étudiant. Il appelle le constructeur de la classe de base en lui passant les arguments spécifiés : de cette façon, nous pouvons définir les variables mPrenom et mNom de la classe Personne sur les mêmes valeurs que celles transmises au constructeur d’Étudiant.
Si nous souhaitions que le nom de la personne, indépendamment de ce qui est indiqué dans le constructeur d’Étudiant, soit toujours “Pippo”, alors que le nom de famille resterait modifiable, il suffirait d’écrire :
: base("Pippo", Nom)
Ceci est nécessaire car lors de la création d’un objet d’une classe dérivée d’une autre, la classe de la classe dérivée est appelée par la classe de la classe de base : dans notre exemple, lors de l’instanciation d’un objet Étudiant, le constructeur de la classe Personne est d’abord appelé, et après celui d’Étudiant.
Puisque la classe Personne n’a pas de constructeur sans arguments, on devrait l’indiquer explicitement avec le mot-clé “base” que le constructeur appelle. Si, d’autre part, Personne avait un constructeur sans argument, «base» ne serait pas servi.
En plus de cela, “base” sert généralement à avoir accès aux méthodes, variables et propriétés de la classe dérivée. Le correspondant “base” dans Visual Basic est le mot clé MyBase.
Essayons de déclarer des objets Personne et Étudiant, pour obtenir le résultat suivant :
Etudiant etud = new Etudiant("Marc", "", 0); etud.Matricule = 232440; // Correct : Matricule est une propriété de la classe Étudiant etud.Nom = "Minerva"; // Correct : Le nom de famille est une propriété héritée par Personne
Personne pers = new Personne("Marc", ""); pers.Nom = "Minerva"; // Correct : Le nom de famille est une propriété de la propriété pers.Matricule = 232440; // Incorrect: la propriété Matricule n'est pas visible depuis Personne
Sans les instructions : Personne et : base (Prénom, Nom) dans la classe Étudiant, éliminerions l’héritage et nous obtiendrions un message d’erreur sur cette instruction :
etud.Nom = "Minerva"
Grâce à l’héritage, lorsqu’une certaine classe est attendue, il est presque toujours possible d’utiliser une classe dérivée. C’est probablement l’un des aspects les plus intéressants de l’héritage.
Par exemple, supposons que nous ayons une fonction qui a deux arguments de type Personne et qui retourne vrai si leurs noms sont les mêmes :
public static bool NomsIdentiques(Personne p1, Personne p2) { return (p1.Prenom == p2.Prenom); }
En tant qu’arguments de cette fonction, les deux instances de la classe Personne et les instances de toutes les classes héritées par la personne peuvent être transmises, ainsi que les objets de la classe Étudiant. En fait, comme elle hérite de la personne, il a toutes les propriétés publiques de la classe de base (en d’autres termes, un étudiant est une personne, donc il peut être utilisé dans tous les contextes où une personne est requise). Le code suivant est correct :
Personne pers = new Personne("Marc", "Rossi"); Etudiant etud = new Etudiant("Marc", "Minerva", 232440); Console.WriteLine(NomsIdentiques(pers, etud)); // Affiche true
Un fait très intéressant est qu’à l’intérieur de la routine NomsIdentiques, la variable etud est vue comme une personne, et par conséquent, les méthodes et les propriétés publiques de la classe Personne sont visibles, et pas celles d’Étudiant.
L’héritage est unique, en C# comme dans VB.NET, ou une classe ne peut avoir qu’une classe de base, contrairement à C++, qui supporte l’héritage multiple : en d’autres termes, il n’est pas possible de définir une classe C héritant simultanément de A à B. Nous reviendrons sur ces concepts plus tard.
Précédent : 7. String Interpolation en C#, concaténer des chaînes Suivant : 9. Polymorphisme
Étiquette :Structure du langage