Occultation dans Visual Basic

Lorsque deux éléments de programmation partagent le même nom, l’un d’entre eux peut masquer ou mettre l’autre en mémoire fantôme. Dans une telle situation, un élément ombré n’est pas disponible pour référence ; au lieu de cela, lorsque votre code utilise le nom de l’élément, le compilateur Visual Basic le résout en élément d’ombre.

Objectif

L’objectif principal de l’ombre est de protéger la définition de vos membres de classe. La classe de base peut subir une modification qui crée un élément portant le même nom qu'un élément que vous avez déjà défini. Dans ce cas, le modificateur Shadows force les références via votre classe à résoudre en membre que vous avez défini, au lieu du nouvel élément de classe de base.

Types d’ombre

Un élément peut ombrer un autre élément de deux façons différentes. L’élément d’ombre peut être déclaré à l’intérieur d’une sous-région contenant l’élément ombré, auquel cas l’ombre est effectuée à travers l’étendue. Ou une classe dérivante peut redéfinir un membre d’une classe de base, auquel cas l’ombre est effectuée via l’héritage.

Ombre à travers l’étendue

Il est possible que les éléments de programmation dans le même module, classe ou structure aient le même nom mais une étendue différente. Lorsque deux éléments sont déclarés de cette façon et que le code fait référence au nom qu’ils partagent, l’élément avec l’étendue plus restrictive ombre l’autre élément (l’étendue de bloc est la plus restrictive).

Par exemple, un module peut définir une variable Public nommée temp, et une procédure dans le module peut déclarer une variable locale également nommée temp. Les références à temp à l'intérieur de la procédure accèdent à la variable locale, tandis que les références à temp à l'extérieur de la procédure accèdent à la variable Public. Dans ce cas, la variable de procédure temp ombre la variable de module temp.

L’illustration suivante montre deux variables nommées temp. La variable locale temp ombre la variable membre temp lorsqu’elle est accédée à partir de sa propre procédure p. Toutefois, le mot clé MyClass contourne l’ombre et accède à la variable membre.

Graphic that shows shadowing through scope.

Pour obtenir un exemple d’ombre à travers l’étendue, consultez Comment : masquer une variable portant le même nom que votre variable.

Ombre via l’héritage

Si une classe dérivée redéfinit un élément de programmation hérité d’une classe de base, l’élément de redéfinition ombre l’élément d’origine. Vous pouvez ombrer n’importe quel type d’élément déclaré, ou ensemble d’éléments surchargés, avec n’importe quel autre type. Par exemple, une variable Integer peut ombrer une procédure Function. Si vous ombrez une procédure avec une autre procédure, vous pouvez utiliser une liste de paramètres différente et un autre type de retour.

L’illustration suivante montre une classe de base b et une classe dérivée d qui hérite de b. La classe de base définit une procédure nommée proc et la classe dérivée l’ombre avec une autre procédure du même nom. La première instruction Call accède au proc d’ombre dans la classe dérivée. Toutefois, le mot clé MyBase contourne l’ombre et accède à la procédure ombrée dans la classe de base.

Graphic diagram of shadowing through inheritance

Pour obtenir un exemple d’ombre par héritage, consultez Comment : masquer une variable portant le même nom que votre variable et Comment : masquer une variable héritée.

Ombre et niveau d’accès

L’élément d’ombre n’est pas toujours accessible à partir du code à l’aide de la classe dérivée. Par exemple, il peut être déclaré Private. Dans ce cas, l’ombre est rejeté et le compilateur résout toute référence au même élément qu’il aurait s’il n’y avait pas eu d’ombre. L’élément est celui accessible qui est le moins éloigné de la classe d’ombre. Si l'élément ombré est une procédure, la résolution se fait sur la version accessible la plus proche ayant le même nom, la même liste de paramètres et le même type de retour.

L’exemple suivant montre une hiérarchie d’héritage de trois classes. Chaque classe définit une procédure Subdisplay, et chaque classe dérivée ombre la procédure display dans sa classe de base.

Public Class firstClass  
    Public Sub display()  
        MsgBox("This is firstClass")  
    End Sub  
End Class  
Public Class secondClass  
    Inherits firstClass  
    Private Shadows Sub display()  
        MsgBox("This is secondClass")  
    End Sub  
End Class  
Public Class thirdClass  
    Inherits secondClass  
    Public Shadows Sub display()  
        MsgBox("This is thirdClass")  
    End Sub  
End Class  
Module callDisplay  
    Dim first As New firstClass  
    Dim second As New secondClass  
    Dim third As New thirdClass  
    Public Sub callDisplayProcedures()  
        ' The following statement displays "This is firstClass".  
        first.display()  
        ' The following statement displays "This is firstClass".  
        second.display()  
        ' The following statement displays "This is thirdClass".  
        third.display()  
    End Sub  
End Module  

Dans l’exemple précédent, la classe dérivée secondClass ombre display avec une procédure Private. Lorsque le module callDisplay appelle display dans secondClass, le code appelant est en dehors de secondClass et ne peut donc pas accéder à la procédure privée display. L’ombre est rejeté et le compilateur résout la référence à la procédure display de la classe de base.

Cependant, la classe dérivée thirdClass supplémentaire déclare display comme Public, de sorte que le code dans callDisplay peut y accéder.

Ombre et substitution

Ne confondez pas l’ombre et la substitution. Les deux sont utilisées lorsqu'une classe dérivée hérite d'une classe de base, et les deux redéfinissent un élément déclaré avec un autre. Mais il existe des différences significatives entre les deux. Pour une comparaison, consultez Différences entre l’ombre et la substitution.

Ombre et surcharge

Si vous ombrez le même élément de classe de base avec plusieurs éléments de votre classe dérivée, les éléments d’ombre deviennent des versions surchargées de cet élément. Pour plus d'informations, consultez Procedure Overloading.

Accès à un élément ombré

Lorsque vous accédez à un élément à partir d’une classe dérivée, vous le faites normalement via l’instance actuelle de cette classe dérivée, en qualifiant le nom d’élément avec le mot clé Me. Si votre classe dérivée ombre l’élément dans la classe de base, vous pouvez accéder à l’élément de classe de base en le qualifiant avec le mot clé MyBase.

Pour obtenir un exemple d’accès à un élément ombré, consultez Comment : accéder à une variable masquée par une classe dérivée.

Déclaration de la variable objet

La façon dont vous créez la variable objet peut également affecter si la classe dérivée accède à un élément d’ombre ou à l’élément ombré. L’exemple suivant crée deux objets à partir d’une classe dérivée, mais un objet est déclaré comme classe de base et l’autre comme classe dérivée.

Public Class baseCls  
    ' The following statement declares the element that is to be shadowed.  
    Public z As Integer = 100  
End Class  
Public Class dervCls  
    Inherits baseCls  
    ' The following statement declares the shadowing element.  
    Public Shadows z As String = "*"  
End Class  
Public Class useClasses  
    ' The following statement creates the object declared as the base class.  
    Dim basObj As baseCls = New dervCls()  
    ' Note that dervCls widens to its base class baseCls.  
    ' The following statement creates the object declared as the derived class.  
    Dim derObj As dervCls = New dervCls()  
    Public Sub showZ()
    ' The following statement outputs 100 (the shadowed element).  
        MsgBox("Accessed through base class: " & basObj.z)  
    ' The following statement outputs "*" (the shadowing element).  
        MsgBox("Accessed through derived class: " & derObj.z)  
    End Sub  
End Class  

Dans l’exemple précédent, la variable basObj est déclarée comme classe de base. L’attribution d’un objet dervCls constitue une conversion étendue et est donc valide. Toutefois, la classe de base ne peut pas accéder à la version d’ombre de la variable z dans la classe dérivée, de sorte que le compilateur résout basObj.z à la valeur de classe de base d’origine.

Voir aussi