M12 Programmation Orientee Objet

  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View M12 Programmation Orientee Objet as PDF for free.

More details

  • Words: 6,987
  • Pages: 20
Leçon 2 : Portées de vos déclarations Les principales portées sont Public, Private, Friend et Protected. Une classe peut contenir des attributs ou des méthodes, qui peuvent être de chacuns des 4 types pré-cités : - Ceux qui sont Public sont accessibles suite à la création de l'objet. - Ceux qui sont Private ou Protected ne sont accessibles qu'à l'intérieur même du module de classe. - Les membres Protected sont similaires aux Private, mais ils ont une particularité en cas d'héritage. Ce point sera abordé plus tard dans la leçon correspondante. - Les membres Friend ne sont accessibles qu'à l'intérieur du projet, et pas par des éléments extérieurs au projet en cours. Continuons sur notre exemple et importons l'espace de noms System : Imports System

L'instruction de début de notre espace de noms : Animaux (Tout le code qui suit en fera partie) Namespace Animaux

Chien est une classe appartenant à l'espace de noms Animaux : Public Class Chien 'Voici une variable public Public AgeDuChien as Integer

Aboie est une fonction publique (Public) de notre classe Chien : Public Function Aboie() Console.Writeline ("Le chien aboie !") End Function

Et Marche en est une autre, déclarée en privée (Private) : Private Function Marche() Console.Writeline ("Le chien marche") End Function End Class End Namespace

Passons maintenant à notre module : Public Module modMain

L'exécution va démarrer à partir de la procédure Main() : Sub Main() 'Appelle notre fonction (cf. ci-dessus) MaFonction() End sub 'MaFonction: Appelée à partir de la procédure Main() Function MaFonction() Dim Jimmy as Animaux.Chien Jimmy = New Animaux.Chien() 'Ce qui suit fonctionnera, car Aboie et AgeDuChien sont Public Jimmy.Aboie() Jimmy.AgeDuChien = 10 'Par contre, l'appel de la fonction Marche() échouera, car il se situe en dehors 'du module de classe Chien 'Donc le code qui suit est incorrect : décommentez-le 'et essayez de compiler, vous obtiendrez une erreur ! 'Jimmy.Marche() End Function End Module

1/22

Leçon 3 : Fonctions Partagées Dans une classe, les membres partagés (propriétés et méthodes) peuvent être appelés directement, sans passer par l'instanciation d'un objet (comme précédement décrit). Le mot-clé Shared indique en effet que la propriété ou méthode ne s'appuie pas sur un objet spécifique mais bien sur la classe elle-même, et qu'elle peut être appelée directement à partir de cette classe, même si celle-ci n'a aucune instance en cours. Une propriété Shared contient quant à elle une valeur commune à tous les objets d'une classe. Notre exemple démarre de manière habituelle, avec l'import de l'espace de noms System, l'instruction de début de notre espace de noms, Animaux, et une classe lui appartenant, Chien : Imports System Namespace Animaux Class Chien

Et Aboie est maintenant une fonction Public et Shared de cette classe : Public Shared Function Aboie() Console.Writeline ("Le chien aboie !") End Function

Marche, quant à elle, est une fonction Public, mais non partagée. Public Function Marche() Console.Writeline ("Le chien marche ...") End Function End Class End Namespace

Démarrons notre module, l'exécution se fera à partir de la procédure Main() : Public Module modMain Sub Main() 'Nous pouvons faire appel à la méthode Aboie() directement, 'Sans passer par la création d'un objet de type Chien, 'puisque qu'elle est partagée Animaux.Chien.Aboie() 'Par contre, nous ne pourrons utiliser la méthode Marche() 'que suite à la création d'un objet, puisque celle-ci 'n'est pas partagée. Dim Jimmy as Animaux.Chien Jimmy = New Animaux.Chien() Jimmy.Marche() End sub End Module

Réfléchissons un instant! La procédure WriteLine() que nous utilisons depuis le début est une méthode partagée de la classe Console. De même, nous pouvons déclarer la procédure Main() elle-même comme une méthode partagée dans une classe : c'est-à-dire Shared Sub Main(). Essayez de déplacer cette procédure Main() du module dans la classe Chien ci-dessus et testez le résultat !

2/22

Leçon 4 : La Surcharge La surcharge est une technique simple à utiliser, qui permet d'utiliser le même nom de fonction avec des paramètres de différents types. Voyons ce que ça donne sur la classe Addition dans l'exemple qui suit. Comme d'habitude, nous avons besoin de l'espace de noms System : Imports System Class Addition

Ensuite, ajoutons 2 fonctions Add(). La première additionne 2 entiers ... (Convert.ToString est l'équivalent de la fonction CStr de VB6) Overloads Public Sub Add(A as Integer, B as Integer) Console.Writeline ("Adding Integers: " + Convert.ToString(a + b)) End Sub

... et la deuxième concatène 2 chaînes de caractères : Overloads Public Sub Add(A as String, B as String) Console.Writeline ("Adding Strings: " + a + b) End Sub

Et les 2 ont le même noms ? Ceci est possible uniquement car nous avons utilisé le motclé Overloads dans leur déclaration, pour justement spécifier la surcharge ! Ici, voyons ce que ça donne avec la procédure Main() suivante, incluse dans le module de classe Addition (et donc déclarée en tant que partagée, cf paragraphe précédent) : Shared Sub Main() Dim monCalcul as Addition 'Créée l'objet monCalcul = New Addition 'Appel de la première fonction ... monCalcul.Add(10, 20) ' ... et appel de la seconde : monCalcul.Add("Bonjour", " comment allez-vous ?") End Sub End Class

Leçon 5 : L'Héritage L'héritage est un mécanisme par lequel une classe dérivée (ou classe fille) hérite de toutes les caractéristiques de sa classe de base (ou classe mère). En bref, il est possible de créer via héritage vos classes à partir d'une classe existante : Il suffit pour cela d'utiliser le mot-clé Inherits. Voici un exemple simple. Commençons par importer l'espace de noms habituel : Imports System

Voici notre classe de base : Class Humain 'Quelque chose que la plupart des êtres humains font :

3/22

Public Sub Marche() Console.Writeline ("Je marche ...") End Sub End Class

Et maintenant, créons une classe fille nommée Developpeur : Class Developpeur Inherits Humain 'Nous avons donc déjà accès à la méthode Marche() définie cidessus 'Et voici une autre qui illustre ce que certains ‘programmeurs font parfois : Public Sub PiqueDuCode() Console.Writeline ("Je pompe du code ...") End Sub End Class

Ce qui nous permet de coder la procédure MainClass() suivante : Class MainClass 'Notre procédure principale : Shared Sub Main() Dim Tom as Developpeur Tom = New Developpeur 'Cet appel est valide puisque Developpeur a accès à cette fonction 'héritée de la classe Humain : Tom.Marche() 'Celui-ci également puisque Tom est une instance de la classe Developpeur Tom.PiqueDuCode() End Sub End Class

Définition de l'héritage: A partir d'une classe existante, la classe de base (ou classe mère), on peut créer une nouvelle classe,la classe dérivée (ou classe fille) qui héritent des propriétés de la classe de base. La classe fille peut être modifiée. Exemple: Soit la Classe 'Animal4, on peut créer une Classe 'Cheval' qui aura toutes les propriétés de 'Animal'. La Classe 'Cheval' est un 'Animal'. Quant on peut dire 'est un', il s'agit bien d'héritage.

Une classe peut hériter d'une autre classe, il suffit d'utiliser :'Inherits'

Inherits permet de déclarer une nouvelle classe,la classe dérivée (ou classe fille), basée sur une classe existante, la classe de base (ou classe mère). Les classes dérivées héritent des propriétés, des méthodes, des événements, des champs et des constantes de la classe de base et peuvent les étendre.

Voici une classe de base: Class Salarié1

4/22

Public Property SalaireAnnuel() As Integer ... End Property End Class

Créons une classe dérivée qui hérite de Salarié1: Public Class Salarié2 Inherits Salarié1 End Class

On peut ajouter: MustInherit: Cela donne une classe non instanciable, on ne peut pas créer d'objet avec!! Alors à quoi cela sert!! A fournir une base pour des classes qui en hériteront. on appelle ces classes des classes abstraites. NotInheritable: Cette classe ne peut-être héritée.

Membres de la classe dérivée: La classe fille possède tous les membres de la classe mère. Cela si le membre est 'Protected' ou 'Public'; pas s'il est Private.

Exemple:Un variable Private n'est pas visible dans la Classe fille. Un variable Public est visible dans la Classe fille, mais aussi par l'utilisateur de l'objet. Un variable Protected est visible dans la Classe fille mais pas à l'extérieur.

Dans la classe Salarié2 on peut utiliser la méthode SalaireAnnuel.

Il est possible de rajouter des membres propre à la classe fille, mais aussi de redéfinir, de surcharger ou de masquer des membres de la classe mère.

A- Redéfinition de membres (Overrides) Il est possible en plus de redéfinir (de substituer) un des membres de la classe mère dans la classe fille.(de créer une nouvelle définition du membre dans la classe fille et uniquement pour cette classe fille) si besoin. Pour que cela marche il faut que le membre de la classe mère soit modifiable (overridable) et que le membre de même nom de la classe fille soit modifié (Overrides) Dans la Classe fille (classe dérivée): Overrides Indique que cette procédure Sub substitue une procédure de même nom dans une classe de base. Le nombre et les types de données des

5/22

arguments doivent correspondre exactement à ceux de la procédure de la classe de base. Dans la Classe mère (classe de base): Overridable Indique que cette procédure peut être substituée par une procédure de même nom dans une classe dérivée. Overridable est le paramètre par défaut. NotOverridable Indique que cette procédure ne peut pas être substituée dans une classe dérivée. NotOverridable est le paramètre par défaut d'une procédure qui ne se substitue pas à une procédure de classe de base. MustOverride Indique que cette procédure Sub n'est pas implémentée dans cette classe et qu'elle doit l'être dans une classe dérivée pour que cette classe puisse être créée.

Exemple: Créons une Classe Salarié1 avec une méthode 'Salaire annuel sur 13 mois' Class Salarié1 Public Overridable ReadOnly Property SalaireAnnuel() As Integer Get SalaireAnnuel = SalaireMensuel * 13 End Get End Property End Class

Créons maintenant une classe Salarié2 qui hérite de toutes les propriétés public et protected de la classe salarié1 donc la méthode SalaireAnnuel qui est sur 12 mois: Public Class Salarié2 Inherits Salarié1 Public Overrides ReadOnly Property SalaireAnnuel() As Integer Get SalaireAnnuel = SalaireMensuel * 12 End Get End Property End Class Quand on instance un objet avec la classe Salarié1, si on utilise la méthode SalaireAnnuel() il sera calculer sur 13 mois. Quand on instance un objet avec la classe Salarié2, si on utilise la méthode SalaireAnnuel() il sera calculer sur 12 mois. Attention le membre substitué doit avoir la même signature (Les mêmes paramètres).

B- Surcharge de membres (Overloads) Cela crée plusieurs membres de même nom mais avec des signatures différentes. Il peut y avoir une version dans la classe de base et une version surchargée de même nom mais avec une signature différente dans la classe fille. Overloads Indique que ce membre surcharge une ou plusieurs membres définis avec le même nom dans une classe de base. La liste d'arguments de cette déclaration doit être différente de la liste d'arguments de chaque membre surchargé. Les listes doivent différer au niveau de leur nombre d'arguments, de leurs types de données ou des deux. Cela permet au compilateur de distinguer la version à utiliser. Exemple:

6/22

Public Overloads ReadOnly Property SalaireAnnuel( Prime As Integer) As Integer Get SalaireAnnuel = (SalaireMensuel * 12) + Prime End Get End Property Vous ne pouvez pas spécifier Overloads et Shadows dans la même déclaration.

C- Cacher un membre de la classe de base(Shadows)

Shadows Indique que ce membre cache un élément de programmation de même nom ou un ensemble d'éléments surchargés, dans une classe de base. Vous pouvez occulter tout type d'élément déclaré par un autre type. Si vous masquez une procédure avec une autre procédure, les arguments et le type retourné n'ont pas besoin de correspondre à ceux de la procédure de la classe de base. Un élément occulté est indisponible à partir de la classe dérivée qui l'occulte, à moins que l'élément d'occultation soit inaccessible, comme c'est le cas de Private.

MyBase: Dans le membre de la classe fille, on peut avoir besoin d'appeler le membre de la classe mère; on le fait avec MyBase: Public Overrides Property OnPaint() 'on redéfini OnPaint MyBase.OnPaint 'on appelle le OnPaint de la Classe mère ... 'on ajoute de nouvelles choses End Property

Constructeur dans une classe fille: Les membres privés de la classe mère, comme on l'a dit, ne sont pas accessibles à partir de la classe fille. Seuls les membres 'Public' et 'Protected' de la classe mère sont accessibles à partir de la classe fille, il faut donc utiliser ces membres dans la classe fille. Exemple avec un constructeur: Public Class Mere 'Attribut privé Private _Nom As String 'Constructeur Public Sub New( ByVal Nom As String) _Nom=Nom End Sub End Class

Public Class Fille Inherits Mere 'Constructeur Public sub New ( ByVal Nom As String) MyBase.New (Nom) End Sub End Class

7/22

On voit ici que dans la classe fille, on appelle le constructeur de la classe mère. Car dans la classe fille _Nom de la classe mère n'est pas accessible. Dans une clase fille, on passe donc les paramètres à la classe mère en utilisant les membres 'Public' ou 'Protected' de cette classe mère, on initialise en plus directement les attributs propres à la classe fille si ils existent.

Héritage successif:exemple: Une classe peut hériter d'une classe qui en hérite d'une autre: Prenons l'exemple suivant : C hérite de B qui hérite de A, les membres sont hérités s'il sont Overridable. Class A Public Overridable Sub F() ' le membre F pourra être modifié dans une classe fille Console.WriteLine("A.F") End Sub Public Overridable Sub G()'le membre G pourra être modifié dans une classe fille Console.WriteLine("A.G") End Sub End Class Class B Inherits A 'Hérite de A Public Overrides NotOverridable Sub F() de F dans une Classe fille Console.WriteLine("B.F") End Sub Public Overrides Sub G() Console.WriteLine("B.G") End Sub End Class

'On interdit la modification

Class C 'Hérite de B qui hérite de A Inherits B Public Overrides Sub G() Console.WriteLine("C.G") End Sub End Class N.B : En VB.Net une Classe ne peut hériter que d'une seule Classe.

8/22

UN AUTRE COURS I. Introduction II. Prerequis III. Définitions III-A. L'héritage III-B. Le polymorphisme III-C. Signature de paramètres d'une méthode IV. La surcharge de méthodes V. La redéfinition de méthodes VI. L'occultation VII. Différences entre redéfinition et occultation VIII. Glossaire des mots clés IX. Bibliographie

I. Introduction .NET est la première version de Visual Basic à introduire la notion d'héritage entre classes. Cela a conduit à l'apparition de nouveaux mots clés dont certains se ressemblent par leur syntaxe et d'autres par leur fonctionnement. De ce fait, les développeurs peuvent se trouver facilement perdus. Ainsi, si le concept de surcharge et le rôle du mot clé Overloads sont faciles à comprendre, la confusion entre Overloads et deux mots clés introduits par la redéfinition, Overridable et Overrides, est probable. Même pour les développeurs qui arrivent à passer ce stade sans incident, l'apprentissage de l'occultation et de son mot clé Shadows risque de tout chambouler ! Pour présenter les choses de manière claire, ce tutorial commence par expliquer les notions d'héritage et de polymorphisme nécessaires pour comprendre le reste du document. Ensuite, il aborde les mécanismes de surcharge, de redéfinition et d'occultation en mettant l'accent plus sur le concept que sur les mots clés. Les explications seront appuyées par des exemples simples et chaque paragraphe sera clôturé par une liste des points essentiels à retenir. Beaucoup de livres et articles traitent des concepts abordés dans ce document, le présent tutorial a pour but de faciliter l'assimilation et d'éviter les confusions habituelles. Pour cela, nous allons volontairement éviter certains détails, par exemple, certaines règles spécifiques aux constructeurs, aux évènements et aux membres partagés ne seront pas évoquées.

II. Prerequis La connaissance des bases du langage VB.NET, comme par exemple la syntaxe de déclaration d'une procédure ou d'une fonction, est nécessaire pour bien comprendre ce tutorial. La connaissance des concepts de la programmation orientée objet est particulièrement souhaitable. Par conséquent, si vous ne connaissez pas le langage VB.NET et que vous cherchez à le prendre en main, ce tutorial n'est sûrement pas pour vous.

9/22

III. Définitions Avec sa version .NET, Visual Basic est devenu un véritable langage orienté objet, puisque cette version a introduit les constructeurs de classes, l'héritage entre classes, le polymorphisme et bien d'autres concepts. Même si ce tutorial suppose que vous connaissez les bases de l'orienté objet et la syntaxe correspondante dans Visual Basic .NET, nous allons revenir ici sur quelques définitions qui nous seront utiles par la suite.

III-A. L'héritage L'héritage entre classes consiste en la possibilité de créer une classe, dite classe dérivée, qui englobe toutes les propriétés, les méthodes et les évènements définis dans une autre classe, dite classe de base, sans avoir à les re-saisir. Bien entendu, le principal avantage de l'héritage n'est pas d'éviter la saisie mais surtout d'établir un lien de spécialisation entre les classes. Par exemple, on peut créer une classe Employe en la faisant hériter d'une classe Personne, puisque tout employé est une personne. Ainsi, la classe Employe contiendra automatiquement toutes les caractéristiques de la classe Personne comme le nom et le prénom, et pourra définir des membres spécifiques à un employé comme le salaire par exemple. Dans Visual Basic .NET, la mise en oeuvre de l'héritage passe par l'utilisation du mot clé Inherits, comme le montre l'exemple suivant : Déclaration de la classe de base : Public Class Personne Public titre As String Public nom As String Public prenom As String Public DateDeNaissance As Date End Class

Pour la classe dérivée on utilise le mot clé Inherits et on définit uniquement les membres spécifiques à un employé : Public Class Employe Inherits Personne Public Salaire As Double End Class

Comme la classe Employe englobe automatiquement tous les membres de la classe Personne, le code suivant fonctionne sans problème : Module Execution Sub main() Dim e As New Employe 'On peut faire référence aux membres 'définis dans la classe Personne Console.Out.WriteLine(e.nom & " " & e.prenom) End Sub End Module

Remarque : vous êtes supposés savoir qu'il est déconseillé d'utiliser des champs publics dans les classes, et qu'il faut utiliser des champs Private exposés, si nécessaire, via des propriétés. Dans ce tutorial, cette règle ne sera pas respectée dans le but de condenser le code.

10/22

III-B. Le polymorphisme Le polymorphisme est la possibilité de référencer un objet du type de la classe dérivée avec une variable dont le type est la classe de base, comme dans l'exemple suivant où, à la variable p de type Personne, on affecte un objet Employe, ce code est logiquement correct puisque un employé est en fait une personne : Dim p As Personne p = New Employe

Le polymorphisme garantie aussi autre chose, si une méthode définie dans la classe de base est redéfinie dans une classe dérivée, l'appel à cette méthode à travers une variable de type classe de base va dépendre du type de l'objet pointé par la variable et non pas du type de la variable. Pour clarifier ces propos, considérons l'exemple suivant : La classe Personne définit une méthode affiche() qui affiche les renseignements de la personne, la classe Employe qui dérive de Personne redéfinit la méthode affiche() afin d'afficher aussi le salaire de l'employé. Dans ce cas quel sera le résultat de cette portion de code Dim p As Personne p = New Employe 'Cette instruction affiche aussi le salaire 'car la méthode appelé est celle de la classe 'employe p.affiche()

Dans la dernière instruction, est-ce que c'est la méthode définie dans la classe Personne qui sera appelée ou bien celle définie dans la classe Employe ? Autrement dit, est-ce que le salaire sera affiché ou non ? Le polymorphisme garantit aussi que, si une méthode appelée soit celle définie dans la classe de l'objet désigné par la variable et non pas celle de la classe de la variable utilisée pour appeler la méthode. Dans notre cas, la variable p utilisée pour appeler la méthode est de type Personne, mais comme elle pointe vers un objet Employe (à cause de l'instruction : p = new Employe) alors la méthode appelée est celle définie dans la classe Employe, et par conséquent le salaire sera affiché.

III-C. Signature de paramètres d'une méthode La signature de paramètres d'une méthode est définie par le nombre, l'ordre et le type de ses paramètres. Par exemple, les deux méthodes suivantes ont la même signature : Sub methode1(ByVal par1 As Integer, ByVal par2 As String, ByRef par3 As String) ... End Sub Sub methode1(ByVal p1 As Integer, ByVal p2 As String, ByVal p3 As String) ... End Sub 1

Nous consacrerons par la suite toute une section sur la redéfinition de méthodes

Remarquez que le nom des paramètres et leur ordre de passage (byval ou byref) n'ont pas d'influence sur la signature. Pour que deux signatures de paramètres soit différentes, il ne faut pas que la différence soit due uniquement à un paramètre optionnel ou uniquement aux types de retour pour les fonctions. Dans les deux exemples suivants le compilateur va générer une erreur. Rappelons qu'il n'est pas possible de 11/22

déclarer dans la même classe deux méthodes avec le même nom et la même signature de paramètres : 'Erreur les deux signatures diffèrent par un paramètre optionnel 'ce qui n'est pas suffisant Sub methode1(ByVal param1 As Integer) ... End Sub Sub methode1(ByVal p1 As Integer, Optional ByVal p3 As String = "") ... End Sub 'Erreur les deux signatures diffèrent uniquement par leur type de retour 'ce qui n'est pas suffisant Function fonction1(ByVal param1 As Integer) As Integer '... End Function Function fonction1(ByVal p1 As Integer) As Date '... End Function

Maintenant que vous avez appris ce que sont l'héritage, le polymorphisme et la signature de méthode, nous pouvons aborder la surcharge, la redéfinition et l'occultation sans risquer aucune ambiguïté.

IV. La surcharge de méthodes Visual Basic .NET autorise la surcharge de méthodes, c'est-à-dire qu'il permet de déclarer dans une même classe plusieurs méthodes ayant le même nom mais des signatures différentes. Lorsque vous écrivez plusieurs versions d'une même méthode dans une classe, s'il n y a aucune méthode portant le même nom dans les classes parentes de cette classe 2 alors vous n'avez besoin d'aucun mot clé particulier pour déclarer vos méthodes, comme dans le cas suivant 3 pour la fonction additionne : Public Class Addition 'Plusieurs version de la fonction additionne 'aucun mot clé particulier n'est nécessaire 'puisque la classe Object ne possède pas une méthode additionne Function additionne(ByVal p1 As Double, ByVal p2 As Double) As Double Return p1 + p2 End Function Function additionne(ByVal p1 As Double, ByVal p2 As Double, _ ByVal p3 As Double) As Double Return p1 + p2 + p3 End Function End Class

En revanche, si la méthode que l'on souhaite surcharger a déjà été définie dans l'une des classes de base, alors chaque version surchargée de la méthode dans la classe en cours doit être précédée par le mot clé Overloads. Dans l'exemple suivant, nous allons écrire la classe AdditionAvancee qui hérite de la classe Addition précédente. Dans cette nouvelle classe, nous allons définir deux nouvelles version de la méthode Additionne, qui prennent respectivement quatre et cinq paramètres. Comme la méthode Additionne a déjà été définie dans la classe de base Addition, alors les deux nouvelles versions de la méthode Additionne doivent être précédées par le mot clé Overloas : 12/22

Public Class AdditionAvancee Inherits Addition Overloads Function additionne(ByVal p1 As Double, ByVal p2 As Double, _ ByVal p3 As Double, ByVal p4 As Double) As Double Return p1 + p2 + p3 + p4 End Function Overloads Function additionne(ByVal p1 As Double, ByVal p2 As Double, _ ByVal p3 As Double, ByVal p4 As Double, ByVal p5 As Double) As Double Return p1 + p2 + p3 + p4 + p5 End Function End Class 2

Rappelons que toutes les classes que vous définissez possèderont une classe de base, car même si vous n'utilisez pas le mot clé Inherits, votre classe héritera implicitement de la classe System.Object 3

On aurait pu écrire une seule méthode additionne qui calcule la somme d'un nombre quelconque de paramètres en utilisant un seul paramètre ParamArray. Or, ce que nous cherchons ici c'est juste un exemple pour illustrer les choses. Ce sera le cas pour plusieurs autres exemples à venir. Dans la classe fille, nous pouvons définir une méthode qui a le même nom et la même signature qu'une méthode de la classe de base en utilisant le mot clé Overloads. Cependant, comme elles ont la même signature ce ne sera pas une surcharge mais une occultation, nous reviendrons un peu plus loin sur ce concept. A retenir •

• •



Nous pouvons définir plusieurs versions d'une même méthode à condition qu'elles aient des signatures différentes. Dans la terminologie orientée objet cela s'appelle la surcharge de méthodes. Lorsque nous définissons une méthode surchargée pour la première fois, aucun mot clé n'est nécessaire. Les méthodes seront écrites normalement. Lorsque nous définissons des versions de surcharge pour une méthode qui a été définie dans l'une des classes de base alors, chaque version doit être précédée par le mot clé Overloads. La surcharge peut s'appliquer aussi aux propriétés, dans ce cas les règles sont les mêmes que pour les méthodes.

V. La redéfinition de méthodes Comme vous le savez déjà, une classe dérivée hérite de toutes les méthodes et propriétés de sa classe de base. Or, il se pourrait qu'une méthode nécessite d'être adaptée à la classe dérivée et non pas reprise en l'état. Considérons à nouveau les deux classes Personne et Employe : Public Class Personne Public titre As String Public nom As String Public prenom As String Public overridable Sub affiche() Console.Out.Write(titre & " " & nom & " " & prenom)

13/22

End Sub End Class

Voici le code de la classe Employe : Public Class Employe Inherits Personne Public Salaire As Double End Class

Dans le cas précédent, la classe Employe va hériter de la méthode affiche définie dans la classe Personne. Or cette méthode n'affiche pas le salaire de l'employé et donc elle est en quelque sorte incomplète pour la classe Employe qui a tout intérêt de l'adapter à ses besoins en la redéfinissant. Nous allons voir comment se fait la redéfinition de méthode. Tout d'abord, il faut savoir que c'est le concepteur de la classe de base qui décide quelles méthodes peuvent être redéfinies. Par défaut, les méthodes ne peuvent pas être redéfinies. Elles doivent être uniquement héritées en l'état ou occultées (le chapitre suivant est consacrée à l'occultation). Pour déclarer une méthode qui peut être redéfinie il faut faire précéder sa déclaration par le mot clé Overridable. Par exemple, voici la déclaration de la méthode affiche() de la classe Personne pour qu'elle soit redéfinissable 4: Public Overridable Sub affiche() Console.Out.Write(titre & " " & nom & " " & prenom) End Sub

Maintenant que nous avons rendu la méthode affiche() virtuelle, nous allons voir comme la redéfinir dans la classe dérivée. Pour cela, il suffit de déclarer dans la classe dérivée une méthode qui a le même nom et la même signature 5 que la méthode virtuelle en faisant précéder sa déclaration par le mot clé Overrides. Comme dans l'exemple suivant pour la classe Employe : 4

Les méthodes qui peuvent être redéfinies sont appelées également méthodes virtuelles.

5

Une méthode de la classe dérivée ne peut redéfinir que la méthode ayant le même nom et la même signature qu'elle dans la classe de base. Public Class Employe Inherits Personne Public salaire As Double 'La classe Personne possède maintenant sa propre méthode affiche 'qui affiche aussi le salaire de l'employé Public Overrides Sub affiche() Console.Out.Write(titre & " " & nom & " " & prenom & " " & salaire) End Sub End Class

Ce qui est important à savoir c'est que la redéfinition de méthodes est totalement compatible avec le polymorphisme. Ainsi, si on appelle la méthode affiche() à partir d'une variable de type Personne, ce n'est pas la méthode définie dans la classe Personne qui sera toujours appelée, car le comportement polymorphique veut que la méthode appelée ne soit pas celle du type de la variable mais du type pointé par la variable. Encore un exemple pour illustrer ces propos : Module Execution Sub main() Dim p As New Personne p.titre = "M." p.nom = "Dubois" p.prenom = "Dupont" 'L'instruction suivante va appeler la méthode affiche 'de la classe Personne p.affiche() Console.Out.WriteLine() Dim e = New Employe e.titre = "Mme" e.nom = "Dupuis"

14/22

e.prenom = "Doloris" e.salaire = 10000 p = e 'La variable p pointe désormais vers un objet Employe p.affiche() End Sub End Module

Dans cet exemple, la première instruction p.affiche() va faire appel à la méthode définie dans la classe Personne, non pas parce que la variable p est de type Personne mais parce qu'elle pointe vers un objet de type Personne. La deuxième instruction p.affiche() va faire appel à la méthode définie dans la classe Employe qui affiche aussi le salaire car la variable p pointe vers un objet Employe. Lors de la redéfinition d'une méthode, l'utilisation du mot clé MyBase pour appeler la méthode de la classe de base peut souvent nous rendre un grand service. Dans l'exemple précédent la méthode affiche() de la classe Employe aurait pu être écrite comme suit : Public Overrides Sub affiche() MyBase.affiche() Console.Out.Write(" " & salaire) End Sub

Autre chose importante à signaler, les méthodes déclarées Overrides (c'est-à-dire qui redéfinissent une méthode de leur classe de base) sont automatiquement virtuelles sans qu'il y ait besoin d'utiliser le mot clé Overridable. Par exemple, une classe Manager qui hérite de la classe Employe peut redéfinir la méthode affiche même si cette méthode n'a pas été déclarée Overridable dans la classe Employe. Pour faire en sorte qu'une méthode redéfinie ne soit plus virtuelle il faut utiliser explicitement le mot clé NotOverridable. Voici le code complet et commenté de la classe Manager : Public Class Manager Inherits Employe Public PrimeResponsabilite As Double 'La classe Manager peut redéfinir la méthode affiche de la classe Employe 'mais en la déclarant NotOverridable les classes qui hériteront de la classe 'Manager ne pourront plus redéfinir cette méthode ! Public NotOverridable Overrides Sub affiche() MyBase.affiche() Console.Out.Write(" " & PrimeResponsabilite) End Sub End Class

A retenir • • •



• •

Pour rendre une méthode redéfinissable il faut faire précéder sa déclaration par le mot clés Overridable. Cette méthode sera appelée alors méthode virtuelle. Pour redéfinir une méthode virtuelle, il suffit de définir une méthode dans la classe dérivée qui a le même nom et la même signature que la méthode virtuelle et dont la déclaration est précédée par le mot clé Overrides. Les méthodes qui redéfinissent des méthodes virtuelles sont automatiquement virtuelles à leur tour. Pour faire en sorte qu'une telle méthode ne soit pas virtuelle il faut précéder sa déclaration par le mot clé NotOverridable. L'appel à une méthode redéfinie est complètement polymorphe. La redéfinition peut s'appliquer aussi aux propriétés, dans ce cas les règles sont les mêmes que pour les méthodes.

Et si on redéfinit une méthode surchargée ? A ce stade, et avant de poursuivre il est important de comprendre exactement la différence entre surcharge et redéfinition et le rôle de chacun des mots clés Overloads, 15/22

Overridable et Overrides. Dans une classe dérivée, on peut à la fois redéfinir une méthode virtuelle (avec une méthode qui a le même nom et la même signature) et surcharger cette méthode (en proposant d'autres méthodes ayant le même nom mais des signatures différentes). Ce cas de figure est en fait très simple, il n y a absolument pas de règles spécifiques, ce sont les règles précédentes qui s'appliquent. Ainsi : - Dans la classe dérivée, toutes les versions surchargées de la méthode doivent être précédées par le mot clé Overloads. - La méthode ayant la même signature que la méthode virtuelle doit être précédée par le mot clé Overrides (puisqu'il s'agit d'une redéfinition). Par conséquent, cette dernière méthode sera précédée à la fois par le mot clé Overloads et le mot clé Overrides. En voici un exemple de la classe Employe qui redéfinie la méthode affiche et lui propose une nouvelle version surchargée : Public Class Employe Inherits Personne Public salaire As Double 'Méthode de redéfinition et de surcharge 'Précédée à la fois par Overloads et Overrides Public Overloads Overrides Sub affiche() Console.Out.Write(titre & " " & nom & " " & prenom & " " & salaire) End Sub 'Méthode de surcharge seulement précédée par Overloads Public Overloads Sub affiche(ByVal prefixe As String) Console.Out.Write(prefixe & " ") MyClass.affiche() End Sub End Class

VI. L'occultation Nous avons vu dans la section précédente comment redéfinir une méthode de la classe de base et comment celle-ci doit être déclarée virtuelle, avec le mot clé Overridable, pour pouvoir être redéfinie dans les classes dérivées. Or, il se pourrait que l'on ait besoin de redéfinir une méthode qui n'a pas été déclarée virtuelle dans la classe de base. Dans ce cas, si nous avons accès au code source de la classe de base le mieux serait de modifier la classe de base afin de déclarer la méthode avec le mot clé Overridable. En revanche, si la classe de base se trouve dans une DLL alors il n y a pas moyen de rendre la méthode virtuelle et le seul moyen de la remplacer dans la classe dérivée est l'occultation (Shadowing en Anglais). Pour indiquer qu'une méthode occulte la méthode portant le même nom de la classe de base, il suffit de faire précéder la déclaration de cette méthode par le mot clé Shadows 6. Comme dans l'exemple suivant : Public Class Personne Public titre As String Public nom As String Public prenom As String Public Sub affiche() Console.Out.Write(titre & " " & nom & " " & prenom) End Sub Public Sub affiche(ByVal prefixe As String) Console.Out.Write(prefixe & " ") Console.Out.Write(titre & " " & nom & " " & prenom) End Sub End Class Public Class Employe Inherits Personne

16/22

Public salaire As Double 'Cette méthode occulte les deux occurrences de la méthode affiche de la 'classe de Personne Public Shadows Sub affiche() Console.Out.Write(titre & " " & nom & " " & prenom & " " & salaire) End Sub End Class

Dans l'exemple précédent, la méthode affiche() de la classe Personne n'est pas virtuelle et donc pour la remplacer dans la classe Employe nous sommes obligé de la déclarer avec le mot clé Shadows. 6

A vrai dire le mot clé Shadows n'est pas obligatoire, cependant, si vous l'omettez vous obtiendrez un message d'avertissement (warning) du compilateur. Il faut savoir que dans le cas d'une occultation, la méthode déclarée avec le mot clé Shadows occulte toutes les méthodes portants le même nom dans la classe de base (quelque soit leurs signatures), contrairement à la redéfinition où la méthode déclarée avec Overrides qui ne redéfinit que la méthode ayant le même nom et la même signature. Par exemple, dans le code suivant la deuxième instruction va générer une erreur de compilation : Dim e As New Employe e.affiche("Employe :") 'cette instruction va générer une erreur de compilation

Mais pourquoi cette instruction ne se compile pas alors que normalement la classe Employe devait hériter la méthode affiche(ByVal prefixe As String) de la classe Personne. La raison est que la méthode affiche() de la classe Employe occulte toutes les méthodes portants le nom affiche dans la classe Personne, elle les occulte. Cela veut dire qu'elle les supprime de la classe Employe et qu'elle les remplace. Par conséquent, la classe Employe ne contient pas la méthode affiche(ByVal prefixe As String) Autre chose très importante à connaître sur l'occultation, c'est que l'appel à une méthode occultée ne respecte pas le principe du polymorphisme. Autrement dit, quand on fait appel à une méthode occultée, la méthode appelée dépend du type de la variable utilisée pour l'appel et non pas du type de l'objet pointé par cette variable. Cela vous semble flou, examinons le résultat produit par le code suivant : Sub main() Dim p As New Personne p.titre = "M." p.nom = "Dubois" p.prenom = "Dupont" 'L'instruction suivante va appeler la méthode affiche de la classe Personne p.affiche() Console.Out.WriteLine() Dim e = New Employe e.titre = "Mme" e.nom = "Dupuis" e.prenom = "Doloris" e.salaire = 10000 p = e 'La variable p pointe désormais vers un objet Employe p.affiche() End Sub

Dans le code précédent, à la dernière instruction p.affiche() la variable p qui pointe vers un objet Employe. Mais comme la méthode affiche est occultée dans la classe Employe alors l'appel p.affiche() n'est pas polymorphique. Ce qui veut dire que la méthode affiche() appelée est celle de la classe de la variable p (donc Personne) et non pas celle de l'objet pointé par la variable p (Employe). Donc, si vous exécutez le code précédent, la dernière instruction n'affichera pas le salaire de Mme Dupuis. Dernière chose à connaître sur l'occultation, c'est qu'elle permet d'anticiper les 17/22

changements dans la classe de base (dans le cas où celle-ci ne nous appartient pas) et de mettre la classe dérivée à l'abri dans le cas où on ajoute à la classe de base un membre qui a le même nom qu'un membre déjà présent dans la classe dérivée. A retenir • •

• • •

L'occultation sert à remplacer des méthodes dans la classe dérivée qui n'ont pas été déclarées virtuelles dans la classe de base. Pour déclarer une méthode qui occulte tous les membres ayant le même nom dans la classe de base, il faut faire précéder la déclaration de la méthode par le mot clé Shadows. Les membres occultés ne sont pas hérités par la classe dérivée. L'appel des méthodes occultées ne respecte pas le principe du polymorphisme. Si votre besoin est d'adapter le comportement d'une méthode à la classe dérivée, alors la redéfinition est toujours préférable à l'occultation, tant que la redéfinition est possible.

VII. Différences entre redéfinition et occultation Le tableau suivant 7 présente les principales différences entre la redéfinition et l'occultation : Point de comparaison

Objectif

Redéfinition

Occultation

Offre la possibilité de remplacer des méthodes non virtuelles de la classe de base. Permet de Permet d'adapter les protéger la classe dérivée méthodes de la classe de contre des changements base à la classe dérivée futurs dans la classe de tout en respectant le base (au cas où la classe de polymorphisme base ajoute une méthode qui le même nom qu'une méthode de la classe dérivée)

Elément de redéfinition (élément que l'on Méthodes et propriétés utilise pour redéfinir un autre élément) Uniquement la propriété ou la méthode Elément redéfini ayant le même nom et la même signature que l'élément redéfinissant 18/22

N'importe quel membre de la classe

Tous les membres ayant le même nom que l'élément redéfinissant

La méthode de la classe L'élément de la classe dérivée ne peut pas Accessibilité dérivée peut avoir une (Public, private, modifier l'accessibilité accessibilité différente de de la méthode de la ...) celle de l'élément occulté classe de base La classe de base peut Possibilité de indiquer les éléments lecture et redéfinissables avec : d'écriture de Ces attributs peuvent être Overridable et l'élément changés lors d'une MustOverride et les (élément déclaré occultation éléments qui ne peuvent ReadOnly et être redéfinis avec WriteOnly) NotOverridable Dans la classe de base : La classe de base ne peut Overridable, Contrôle de la pas forcer ou annuler MustOverride Dans la l'occultation de ces redéfinition classe dérivée : éléments Overrides C'est la nouvelle version définie dans la classe dérivée qui sera Dans la classe dérivée : Mots clés utilisés héritée. Les méthodes Shadows redéfinies ne seront pas héritées Héritage des Les éléments déclarés avec C'est la nouvelle éléments utilisés version définie dans la Shadows dans la classe pour la classe dérivée qui sera dérivée seront hérités, les redéfinition par héritée. Les méthodes éléments occultés de la les classes qui redéfinit ne seront pas classe de base ne seront pas héritent de la hérités héritées classe dérivée 7 Ce tableau est largement inspiré de l'article MSDN « Differences Between Shadowing and Overriding » que vous trouverez à l'adresse suivante : http://msdn2.microsoft.com/en-us/library/ms172785.aspx

VIII. Glossaire des mots clés Inherits : Mot clé utilisé pour spécifier la classe de base à partir de laquelle la classe en cours va être dérivée. Si ce mot clé n'est pas utilisé, la classe en cours héritera de la classe System.Object MustInherit : Mot clé utilisé avant la déclaration d'une classe pour indiquer que cette classe ne peut pas être instanciée, elle sert seulement à être héritée par d'autres classes. MustOverride : Mot clé utilisé avant la déclaration d'une méthode pour indiquer que celle-ci doit être redéfinie dans toutes les classes dérivées de la classe en cours. Les classes qui possèdent au moins une méthode avec MustOverride doivent être déclarées avec le mot clé MustInherit. 19/22

NotInheritable : Mot clé précédant la déclaration d'une classe qui indique que l'on ne peut pas créer des classes dérivées à partir de cette classe. NotOverridable : Mot clé utilisé avant la déclaration d'une méthode pour indiquer que celle-ci ne peut pas être redéfinie dans les classes dérivées de la classe en cours. Par défaut, les méthodes ne sont pas virtuelles, ce mot clé n'est utile que pour les méthodes déclarées avec Overrides pour qu'elles cessent d'être virtuelles dans les classes dérivées. Overloads : Mot clé utilisé avant la déclaration d'une méthode pour indiquer que celle-ci surcharge les méthodes ayant le même nom dans la classe de base (ou la classe en cours quoique optionnel dans ce cas). Overridable : Mot clé utilisé avant la déclaration d'une méthode pour indiquer que celle-ci est virtuelle et donc peut être redéfinie dans les classes dérivées. Overrides : Mot clé utilisé avant la déclaration d'une méthode pour indiquer qu'elle redéfinit la méthode portant le même nom et ayant la même signature dans la classe de base. Les méthodes déclarées avec ce mot clé sont automatiquement virtuelles. Shadows : Mot clé utilisé avant la déclaration d'un membre pour occulter tous les membres de la classe de base ayant le même nom.

20/22

Related Documents

M12
May 2020 5
Badiou-objet
May 2020 18
Vb+objet
June 2020 7
Wage-m12
October 2019 22