Иллюстрированный самоучитель по VB.NET

       

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


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

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

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

  • Ключевое слово Overridable указывается в базовом классе для методов, которые могут переопределяться производными классами.

  • Ключевое слово Overrides указывается в производном классе для переопределяемых методов.

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

    Ниже приведен примерный вид базового класса 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

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

  • Переопределение допускается только для членов базовых классов, объявленных с ключевым словом Overridable.

  • Если на некоторой стадии построения иерархии классов потребуется запретить дальнейшее переопределение метода в производных классах, этот метод помечается ключевым словом NotOverridable.

    Ключевое слово 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 не позволяет получить доступ к «дедушкам» и «прадедушкам» класса в иерархии наследования; запись вида MyBase.MyBase. MemberFunction недопустима.

  • MyBase является ключевым словом языка. В отличие от Me, MyBase нельзя использовать с оператором Is, присваивать объектным переменным или передавать процедурам в качестве параметра.

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

  • MyBase — ключевое слово, а не реальный объект. Следовательно, MyClass, как и MyBase, нельзя использовать с оператором Is, присваивать объектным переменным или передавать процедурам в качестве параметра (для ссылки на конкретный экземпляр используется ключевое слово Me).

  • Ключевое слово MyClass не позволяет получить доступ к закрытым (Private) членам класса, тогда как Me предоставляет такую возможность.

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


    Содержание раздела