Главная. Учебники по программам для графики и дизайна!! Главная страница сайта.

 

Обращение к функциональности базового класса

В VB .NET существует модификатор Protected, который автоматически предоставляет доступ из производных классов к соответствующему члену класса, будь то метод или переменная класса. Возникает искушение воспользоваться этим модификатором и объявить все поля базового класса с уровнем доступа Protected, чтобы производные классы могли легко и быстро работать с ними. Не поддавайтесь соблазну! Хороший стиль проектирования требует, чтобы модификатор Protected использовался только для методов, но не для переменных. В противном случае нарушается инкапсуляция и теряется возможность проверки данных там, где она должна происходить — в базовом классе. Как и в реальной жизни, здесь действует хороший принцип «доверяй, но проверяй».

Например, в исходное определение класса Employee входят свойства со следующими сигнатурами:

Public Readonly Property TheName() As String

Public Readonly Property Salary() As Decimal

Таким образом, доступ к этим свойствам разрешен всем классам. Чтобы ограничить доступ к свойствам классами, производными от Empl oyee, замените модификатор Publ ic на Protected.

В табл. 5.1 перечислены различные модификаторы уровня доступа, присваиваемые членам классов в иерархии наследования.

Как было сказано выше, функции (но не поля!) с модификаторами Protected и Protected Friend распространены достаточно широко, поскольку они предотвращают доступ к защищенным членам со стороны внешнего кода.

При использовании Protected возникает весьма интересный подвох. К счастью, компилятор вовремя предупредит вас о возможных проблемах. Рассмотрим конкретный пример: допустим, у вас имеется класс GeekFest с методом Boast, который пытается обратиться к свойству Salary класса Programmer (что в конечном счете означает доступ к свойству Sal агу базового класса Empl oyee). Ниже приведен примерный вид программы:

Public Class GeekFest

Private m_Programmers() As Programmer

Sub New(ByVal Programmers() As Programmer)

m_Programmers = Programmers

End Sub

Public Function Boast(ByVal aGeek As Programmer) As String

Return "Hey my salary is " & aGeek.Salary

End Function

End Class

"left"> Таблица 5.1. Модификаторы уровня доступа при наследовании

Модификатор

Описание

Friend Доступ предоставляется только из текущей сборки
Private Доступ предоставляется только объектам базового класса
Protected Доступ ограничивается объектами базового класса и объектами любых производных классов
Protected Friend Доступ предоставляется только из текущей сборки или из классов, производных отданного базового класса (может рассматриваться как комбинация модификаторов Protected и Friend)
Public Доступ к члену класса предоставляется всем, кто имеет доступ к классу в соответствии с модификатором самого класса

Также допустим, что в класс Empl oyee входит свойство Sal агу, доступное только для чтения и помеченное модификатором Protected вместо Public:

Protected Readonly Property Salary() As Decimal

Get

Return MyClass.m_Salary

End Get End Property

В результате компилятор выдает сообщение об ошибке:

C:\vb net book\chapter 5\Examplel\Examplel\Moduleld.vb(19):

'Examplel. Modulel.Employee. Protected Readonly Property Salary()

As Decimal' is Protected.and is not accessible in this context.

Хотя класс Programmer обладает доступом к защищенному свойству Salary в своем коде, объекты Programmer не имеют доступа к этому методу за пределами кода класса Programmer. Подведем итог:

Обращение к Protected-методам базового класса возможно только из объектов производного класса, но не из внешних ссылок на эти объекты за пределами производного класса.

 

Переопределение свойств и методов

В нашем примере, где программист автоматически получает 6-процентное повышение зарплаты вместо 5-процентного, необходимо изменить поведение метода RaiseSalary и отразить в нем автоматическую надбавку. Это называется переопределением функции.

Общие члены классов переопределяться не могут.

В отличие от многих объектно-ориентированных языков синтаксис VB .NET четко показывает, что метод базового класса должен переопределяться в производном классе. Для этого используются два специальных ключевых слова.

Естественно, типы параметров и возвращаемого значения должны совпадать. Если они различаются, происходит не переопределение, а перегрузка.

Ниже приведен примерный вид базового класса Employee с методом RaiseSalary, который может переопределяться в производных классах Programmer, Manager и т. д. Ключевые строки кода выделены жирным шрифтом:

Option Strict On Public Class Employee

Private m_Name As String

Private m_Salary As Decimal

Private Const LIMIT As Decimal = 0.1D

Public Sub New(ByVal theName As String,ByVal curSalary As Decimal)

m_Name =theName

m_Salary =curSalary End Sub

Public Readonly Property TheName()As String

Get

Return m_Name

End Get End Property

Public Readonly Property Salary()As Decimal

Get

Return MyClass.m_Salary

End Get End Property

Public Overridable Overloads Sub RaiseSalary(ByVal Percent As Decimal)

If Percent > LIMIT Then

' Операция запрещена - необходим пароль

Console.WriteLine('NEED PASSWORD TO RAISE SALARY MORE " & _

"THAN LIMIT!!!!") Else

m_Salary =(1 + Percent) * m_Salary

End If

End Sub

Public Overridable Overloads Sub RaiseSalary(ByVal Percent As _

Decimal.ByVal Password As String) If Password ="special"Then

m_Salary =(1 + Percent) * m_Salary

End If

End Sub

End Class

Необязательное ключевое слово Overloads, упоминавшееся в главе 4, указывает на то, что в классе определены несколько версий RaiseSalary.

Класс Employee часто встречается в примерах этой главы. Либо введите его в Visual Studio, либо скачайте исходный текст с сайта www.piter.com, если вы еще не сделали этого ранее.

В нашей модели зарплата программиста повышается вызовом специализированной версии метода RaiseSalary. Производный класс Programmer приведен ниже (как обычно, ключевые строки выделены жирным шрифтом):

Public Class Programmer

Inherits Employee

Public Sub New(ByVal theName As String, ByVal curSalary As Decimal)

MyBase.New(theName, curSalary)

End Sub

Public Overloads Overrides Sub RaiseSalaryCByVal Percent As Decimal)

MyBase.RaiseSalary(1.2D *Percent."special")

End Sub

End Class

Обратите внимание, каким компактным получился производный класс — большая часть функциональности осталась неизменной, поэтому мы просто наследуем ее от базового класса!

В приведенной ниже процедуре Sub Main компилятор генерирует вызов правильной версии метода Rai seSal ary (с 20-процентной надбавкой) для объекта sal 1у, относящегося к классу Programmer:

Sub Main()

Dim sally As New Programmed"Sally". 150000D) sally.RaiseSalary(0.1D)

' С учетом надбавки для программистов

Console.WriteLine(sally.TheName & " salary is now " & sally.Salary())

Console.ReadLine()

End Sub

Подведем итог:

Ключевое слово VB .NET Notlnheritable полностью запрещает наследование от класса. Как правило, наследование запрещается для классов, выполняющих очень важные функции, которые ни в коем случае, на должны изменяться. Многие классы .NET Framework (такие, как String) помечены ключевым словом Notlnheritable именно по этой причине. Впрочем, если требуется запретить переопределение лишь одного члена класса, незачем запрещать наследование для всего класса; достаточно пометить ключевым словом NotOverridable нужный член класса.

По умолчанию переопределение членов классов запрещается (см. описание ключевого слова Shadows ниже в этой главе). И все же ключевое слово NotOverridable рекомендуется использовать, поскольку оно более наглядно выражает намерения программиста.

Иногда при переопределении метода или свойства возникает необходимость вызвать версию базового класса. Допустим, имени каждого программиста в классе Programmer должен предшествовать почетный титул «Code Guru». Ключевое слово MyBase позволяет обратиться к открытому свойству TheName базового класса в производном классе:

Public Overrides Readonly Property TheName() As String

Get

Return "Code Guru " & MyBase.TheName()

End Get

End Property

Учтите, что ключевое слово MyBase обладает рядом ограничений:

С MyBase тесно связано другое ключевое слово — MyClass. Оно гарантирует, что даже в случае переопределения будет вызван метод, определенный в текущем классе, а не какая-то из его переопределенных версий в производных классах. На ключевое слово MyCl ass распространяются те же ограничения, что и на ключевое слово MyBase, о котором упоминалось в предыдущей главе.

На практике ключевое слово MyClass приносит наибольшую пользу в тех случаях, ког-да мы хотим указать на модификацию поведения класса. Замена его на Me не дает нужного эффекта, поскольку ключевое слово Me означает «текущий экземпляр, код которого выполняется в настоящий момент», и попытки применения его в другом контексте лишь сбивают с толку.

 

Hosted by uCoz