• Aucun résultat trouvé

[PDF] Apprentissage du Langage VB.Net ressource de formation | Cours informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Apprentissage du Langage VB.Net ressource de formation | Cours informatique"

Copied!
20
0
0

Texte intégral

(1)

Leçon 2 : Portées de vos déclarations

Les principales portées sontPublic,Private,Friend etProtected. Une classe peut

contenir des attributs ou des méthodes, qui peuvent être de chacuns des 4 types pré-cités :

- Ceux qui sontPublic sont accessibles suite à la création de l'objet.

- Ceux qui sontPrivate ouProtected ne sont accessibles qu'à l'intérieur même du module de classe.

- Les membresProtected sont similaires auxPrivate, mais ils ont une particularité en cas d'héritage. Ce point sera abordé plus tard dans la leçon correspondante.

- Les membresFriend 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 nomsSystem :

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 nomsAnimaux :

Public Class Chien

'Voici une variable public Public AgeDuChien as Integer

Aboie est une fonction publique (Public) de notre classeChien :

Public Function Aboie()

Console.Writeline ("Le chien aboie !") End Function

EtMarche 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édureMain() :

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

(2)

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

EtAboie est maintenant une fonctionPublic etShared de cette classe :

Public Shared Function Aboie()

Console.Writeline ("Le chien aboie !") End Function

Marche, quant à elle, est une fonctionPublic, 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édureMain() :

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édureWriteLine() que nous utilisons depuis le début est une méthode partagée de la classeConsole.

De même, nous pouvons déclarer la procédureMain() elle-même comme une méthode partagée dans une classe :

c'est-à-direShared SubMain().

Essayez de déplacer cette procédureMain() du module dans la classeChien ci-dessus et testez le résultat !

(3)

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 nomsSystem :

Imports System Class Addition

Ensuite, ajoutons 2 fonctionsAdd(). 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 mot-cléOverloads dans leur déclaration, pour justement spécifier la surcharge !

Ici, voyons ce que ça donne avec la procédureMain() suivante, incluse dans le module de classeAddition (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

(4)

Public Sub Marche()

Console.Writeline ("Je marche ...") End Sub

End Class

Et maintenant, créons une classe fille nomméeDeveloppeur :

Class Developpeur Inherits Humain

'Nous avons donc déjà accès à la méthode Marche() définie ci-dessus

'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édureMainClass() 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:

(5)

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

(6)

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:

(7)

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

(8)

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() 'On interdit la modification de F dans une Classe fille

Console.WriteLine("B.F") End Sub

Public Overrides Sub G() Console.WriteLine("B.G") End Sub

End Class

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

(9)

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.

(10)

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.

(11)

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

(12)

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 classe2 alors vous n'avez besoin d'aucun mot clé particulier pour déclarer vos méthodes, comme dans le cas suivant3 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 :

(13)

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()

(14)

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 signature5 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"

(15)

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,

(16)

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é Shadows6. 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

(17)

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.

(18)

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 suivant7 présente les principales différences entre la redéfinition et l'occultation :

Point de

comparaison Redéfinition Occultation

Objectif

Permet d'adapter les méthodes de la classe de base à la classe dérivée tout en respectant le polymorphisme

Offre la possibilité de remplacer des méthodes non virtuelles de la classe de base. Permet de protéger la classe dérivée contre des changements futurs dans la classe de base (au cas où la classe de 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 utilise pour redéfinir un autre élément)

Méthodes et propriétés N'importe quel membre de la classe

Elément redéfini

Uniquement la

propriété ou la méthode ayant le même nom et la même signature que l'élément redéfinissant

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

(19)

Accessibilité (Public, private, ...)

La méthode de la classe dérivée ne peut pas modifier l'accessibilité de la méthode de la classe de base

L'élément de la classe dérivée peut avoir une accessibilité différente de celle de l'élément occulté

Possibilité de lecture et d'écriture de l'élément (élément déclaré ReadOnly et WriteOnly)

La classe de base peut indiquer les éléments redéfinissables avec : Overridable et MustOverride et les éléments qui ne peuvent être redéfinis avec NotOverridable

Ces attributs peuvent être changés lors d'une

occultation

Contrôle de la redéfinition

Dans la classe de base : Overridable,

MustOverride Dans la classe dérivée :

Overrides

La classe de base ne peut pas forcer ou annuler l'occultation de ces éléments

Mots clés utilisés

C'est la nouvelle version définie dans la classe dérivée qui sera héritée. Les méthodes redéfinies ne seront pas héritées

Dans la classe dérivée : Shadows

Héritage des éléments utilisés pour la

redéfinition par les classes qui héritent de la classe dérivée

C'est la nouvelle version définie dans la classe dérivée qui sera héritée. Les méthodes redéfinit ne seront pas héritées

Les éléments déclarés avec Shadows dans la classe dérivée seront hérités, les éléments occultés de la classe de base ne seront pas hérités

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.

(20)

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.

Références

Documents relatifs

Fig. 7: An Example of non-declared sponsored post: 1) A verified Mega influencer holding a box on her hand and promoting products. 2) The product page is tagged in the photo

Este trabalho mostra a preocupação com os avanços em uma área problema relacionada a apresentação de informações sobre recursos naturais para serem usadas em planejamento

La seconde partie de cette thèse s'attache à construire un mécanisme de régula- tion qui minimise le dommage lié à la dégradation de la qualité de l'eau, maintienne une activité

Ces matériaux ont été développés suivant trois axes principaux : d’abord l’axe des mouvements, associés aux moyens de transport et aux centres névralgiques

Le texte de Roland Marchal dans ce dossier met ainsi l’accent sur cette génération de civils arrivée aux postes de responsabilité depuis la fin des années 1990, et qui

Or en 2004-2005, pour la première fois depuis 1992, les États-Unis plaident fortement en faveur d’une importante opération de paix (de dix mille hommes) dans un conflit africain,

Le coût des incendies de résidences lié au tabac est obtenu directement selon les chiffres publiés dans le rapport des coûts de l’abus de substance au Canada (2006) et qui sont

L’Etat est devenu un agent économique déclinant, ce qui ne manque pas de poser la question de la permanence des services publics dans leur contenu et leur importance