Поделиться через


Тени в Visual Basic

Если два элемента программирования имеют одно и то же имя, один из них может скрыть или затенить другой. В такой ситуации теневой элемент недоступен для ссылки; вместо этого, когда код использует имя элемента, компилятор Visual Basic разрешает его как затеняющий элемент.

Цель

Основной целью скрытия является защита определения членов вашего класса. Базовый класс может измениться таким образом, что создаст элемент с тем же именем, как у уже определённого. Если это случается, модификатор Shadows принуждает ссылки через ваш класс разрешаться на определенный вами элемент, вместо того чтобы вести к новому элементу базового класса.

Типы тени

Элемент может затенять другой элемент двумя разными способами. Элемент затенения можно объявить внутри подрегиона региона, содержащего затеняемый элемент, при этом затенение осуществляется через область видимости. Или производный класс может переопределить член базового класса, и в этом случае затенение происходит через наследование.

Тени в пределах области

Элементы программирования в одном модуле, классе или структуре могут иметь одинаковое имя, но разную область видимости. Когда два элемента объявляются подобным образом, и код ссылается на общее имя, элемент с более узкой областью видимости затеняет другой элемент (область блока является самой узкой).

Например, модуль может определить Public переменную с именем temp, и процедура в модуле может объявлять локальную переменную также с именем temp. Ссылки на temp изнутри процедуры обращаются к локальной переменной, в то время как ссылки на temp извне процедуры обращаются к переменной Public. В этом случае переменная процедуры temp скрывает переменную модуля temp.

На следующем рисунке показаны две переменные с именами temp. Локальная переменная temp скрывает член класса temp, когда к ней обращаются внутри её собственной процедуры p. Однако ключевое MyClass слово проходит тень и обращается к переменной-члену.

Рисунок, показывающий тени через прицел.

Пример сокрытия через область видимости см. в статье "Практическое руководство: Скрыть переменную с таким же именем, как и у вашей переменной".

Затенение через наследование

Если производный класс переопределяет элемент программирования, унаследованный от базового класса, переопределяющий элемент затмевает исходный элемент. Вы можете затмевать любой тип объявленного элемента или любой набор перегруженных элементов, используя любой другой тип. Например, переменная Integer может затенить процедуру Function . Если вы замещаете одну процедуру другой, вы можете использовать другой список параметров и другой тип возвращаемого значения.

На следующем рисунке показан базовый класс b и производный класс d , наследующий от b. Базовый класс определяет процедуру с именем proc, а производный класс заменяет её другой процедурой с тем же именем. Call Первая инструкция обращается к тени proc в производном классе. Однако ключевое MyBase слово обходит теневой эффект и получает доступ к защищенной процедуре в базовом классе.

Графическая схема затенения с помощью наследования

Пример теневого наследования см. в статье "Практическое руководство. Скрытие переменной с тем же именем, что и переменная и практическое руководство. Скрытие унаследованной переменной".

Отслеживание и Уровень доступа

Элемент тени не всегда доступен из кода с помощью производного класса. Например, его можно объявить Private. В таком случае затенение устраняется, и компилятор разрешает проблему с любой ссылкой на тот же элемент, как если бы затенения не существовало. Этот элемент является доступным элементом, который находится на минимальном количестве производных шагов назад от теневого класса. Если теневой элемент является процедурой, разрешение — к ближайшей доступной версии с тем же именем, списком параметров и типом возвращаемого значения.

В следующем примере показана иерархия наследования трех классов. Каждый класс определяет процедуру, и каждый производный класс перекрывает эту процедуру в своем базовом классе.

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  

В предыдущем примере производный класс secondClass затеняет display процедурой Private. Когда модуль callDisplay вызывает display в secondClass, код вызова находится вне secondClass и поэтому не может получить доступ к закрытой процедуре display. Проблема теневого связывания решена, и компилятор обращается к процедуре базового класса display.

Однако дальнейший производный класс thirdClass объявляет display как Public, так что код в callDisplay может получить к нему доступ.

Затенение и переопределение

Не путайте тени с переопределением. Оба используются, когда производный класс наследует от базового класса, и оба переопределяют один объявленный элемент с другим. Но между этими двумя существуют значительные различия. Сравнение см. в разделе "Различия между теневым и переопределением".

Тень и перегрузка

Если вы скрываете один и тот же элемент базового класса с помощью нескольких элементов в производном классе, элементы скрытия становятся перегруженными версиями этого элемента. Дополнительные сведения см. в разделе "Перегрузка процедур".

Доступ к теневому элементу

При доступе к элементу из производного класса обычно это делается с помощью текущего экземпляра этого производного класса, указав имя элемента с ключевым словом Me . Если производный класс теняет элемент в базовом классе, вы можете получить доступ к элементу базового класса, квалифицируя его с помощью ключевого MyBase слова.

Пример доступа к теневой элементу см. в статье "Практическое руководство. Доступ к переменной, скрытой производным классом".

Объявление переменной объекта

Создание переменной объекта также может повлиять на то, обращается ли производный класс к элементу, затмевающему, или к затмеваемому элементу. В следующем примере создаются два объекта из производного класса, но один объект объявлен как базовый класс, а другой — производным классом.

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  

В предыдущем примере переменная basObj объявляется как базовый класс. Назначение dervCls объекта ему представляет собой расширение преобразования, поэтому является допустимым. Однако базовый класс не может получить доступ к теневой версии переменной z в производном классе, поэтому компилятор разрешает basObj.z как первоначальное значение базового класса.

См. также