:: Меню ::

Головна
  • Про сайт
  • Введення
  • Середовище програмування VB .NET: Visual Studio .NET
  • Вирази, оператори і передача управління
  • Класи і об'єкти
  •  Спадкоємство і інтерфейси
  • Обробка подій і делегати
  • Обробка помилок в VB .NET
  • Форми Windows, графічний вивід і друк
  • Уведення-виведення
  •  Багатопотокові застосування
  • Підтримка баз-даних в VB .NET
  • Короткий огляд ASP .NET
  • Складки .NET, установка додатків і COM Interop
  • Книга для гостей
    Контакти
    Добавити у вибране

    :: Друзі ::

     
     

    :: Лічильники ::

    = =

     

     

     

     

    Як стати начальником?

    Припустимо, ви побудували чудову об'єктно-орієнтовану систему обліку кадрів, в якій повною мірою використовуються всі переваги поліморфізма. А зараз спробуйте відповісти на просте питання — як у вашій системі реалізований переклад простого працівника в менеджери?

    Як не дивно, в ООП подібні операції (тобто зміна типу поточного екземпляра в об'єктно-орієнтованій програмі) вважаються за один з складних аспектів архітектури додатку, про який зазвичай ніхто серйозно не думає, поки ситуація не стане критичною. Відповідно до специфіки об'єктно-орієнтованого програмування після створення об'єкту змінити його тип неможливо.

    У нашій системі обліку кадрів існує тільки одне прийнятне рішення — включити в клас Employee метод, який копіює стан Employee в новий об'єкт Manager, після чого позначає старий об'єкт Employee як невживаний.

    Проглядання ієрархії спадкоємства

    З ускладненням ієрархії класів в програмі на допомогу приходить вікно класів і Object Browser. Наприклад, з вікна класів на мал. 5.1 видно, що клас Programmer є похідним від класу Employee і перевизначає тільки конструктор і метод Raisesalary.

    Мал. 5.1. Ієрархія спадкоємства у вікні класів


    Програми, засновані на UML (зокрема, Visio або Rational Rose), не тільки ото-бражают зв'язки між класами в ієрархії спадкоємства, але і генерують «скелет» програми. Одні програмісти в захваті від систем автоматизованого програмування, інші їх ненавидять.

    Правила перетворення і звернення до членів класів в ієрархії спадкоємства

    Об'єкти похідних класів можуть зберігатися в змінних базових класів:

    Dim tom As New Programmer("Tom". 65000)

    Dim employeeofthemonth As Employee

    employeeofthemonth = torn

    У режимі жорсткої перевірки типів (Option Strict On), якщо об'єкт tom зберігається в змінній employeeofthemonth, для збереження його в змінній Programmer доводиться використовувати функцію Стуре, оскільки компілятор заздалегідь не знає, що таке перетворення можливе:

    Dim programrneroncall As Programmer

    programmeroncal1 = Ctype(employeeofthemonth,programmer)

    Звичайно, просте збереження tom в змінній programmeroncall виконується простим привласненням.

    При роботі з об'єктом torn через змінну employeeofthemonth вам не вдасться використовувати унікальні члени, визначені в класі Programmer і відсутні в Employee. З іншого боку, як буде показано в наступному розділі, при цьому зберігається доступ до всіх членів класу Programmer, переопределяющим члени класу Employee.

    Поліморфізм на практиці

    Спадкоємство часто допомагає позбавитися від громіздких конструкцій Select Case і If-then-else, щоб вся чорнова робота виконувалася компілятором і механізмом поліморфізму. Наприклад, цикл з наступного фрагмента працює як з екземплярами класу Employee, так і з екземплярами Programmer:

    Sub Maln()

    Dim tom As New Employee("Tom". 50000)

    Dim sally As New Programmer("Sally", 150000)

    Dim ouremployees(l) As Employee ourempl.oyees(0)=tom

    ouremployees(l)= Sally

    Dim anemployee As Employee

    For Each anemployee In ouremployees

    anemployee.RaiseSalary(0.1d)

    Console.WriteLine(anemployee.TheName & "salary now is " & _

    anemployee.Salary()) Next

    Console. Readline()

    End Sub

    Результат виконання цього прикладу показаний на мал. 5.2. Ми бачимо, що в кожному випадку викликається правильний метод Raisesalary, не дивлячись на те що в масиві типу Employee зберігаються як об'єкти Employee, так і об'єкти Programmers.

    Мал. 5.2. Використання поліморфізму в програмі

    Іноді говорять, що в VB .NET за умовчанням методи є віртуальними. Термін «віртуальний» означає, що при виклику методу компілятор використовує дійсний тип об'єкту замість типу контейнера або посилання на об'єкт.


    У тільки що розглянутому прикладі під віртуальністю слід розуміти, що, хоча всі посилання відносяться до типу Empl oyee (оскільки об'єкти зберігаються в масиві Employee), компілятор перевіряє дійсний тип об'єкту sally (це тип Programmer) для виклику правильного методу Rai sesal агу, що забезпечує велику надбавку.
    Віртуальні методи досить часто використовуються в ситуаціях, коли в контейнері базового типу зберігаються об'єкти як базового, так і похідного типу. Втім, наш спрощений підхід до виклику віртуальних методів зв'язаний з деякими небезпеками. Модифікація класу Programmer і включення в нього унікальних членів порушують нормальну роботу поліморфізму. У наступному прикладі клас Programmer доповнюється двома новими членами (полемо і властивістю), виділеними жирним шрифтом:

    Public Class Programmer

    Inherits Employee

    Private m_gadget As String

    Public Sub New(Byval thename As String.

    Byval cursalary As Decimal)
    Mybase.New(thename. cursalary)

    End Sub

    Public Overloads Overrides Sub Raisesalary(Byval Percent As Decimal)
    Mybase.RaiseSalary(1.2d * Percent, "special")

    End Sub
    Public Property Computergadget() As String Get
    Return m_gadget End Get Setcbyval Value As String)
    m_badget = Val ue

    End Set

    End Property

    End Class


    У процедуру Sub Main додаються нові строчки, виділені жирним шрифтом:


    Sub Main()
    Dim tom As New Employee("Tom". 50000)
    Dim sally As New Programmed"sally". 150000)
    sally.ComputerGadget = "Ipaq"
    Dim ouremployees.d) As Employee
    ouremployees(0)= tom
    ouremployees(l)= sally
    Dim anemployee As Employee
    For Each anemployee In ouremployees
    anemployee.RaiseSalary(0.1d)
    Console.WriteLine(anemployee.TheName & "salary now is "
    & anemployee.Salary()) Next

    Console.WriteLine(ouremployeesd).TheName & "gadget is an "_
    & ourenployees(l).Gadget) Console. Readline()

    End Sub

    При спробі відкомпілювати новий варіант програми буде видано повідомлення про помилку:

    C:\book to comp\chapter 5\virtualproblems\virtualproblems\modulel.vb(17): The name 'Gadget'is not а member of 'Virtualproblems.Employee1.

    Хоча об'єкт sally, що зберігається в елементі масиву ouremployees(l), відноситься до типу Programmer, компілятор цей не знає і тому не може знайти властивість Computergadget. Більш того, при включеному режимі Option Strict (а відключати його не рекомендується) для використання унікальних членів класу Programmer вам доведеться проводити явне перетворення елементів масиву до типу Programmer:

    Console.WriteLine(ouremployees(l).TheName & "gadget is an " & _

    Ctype(ouremployeesd), Programmer).ComputerGadget)

    Перетворення об'єкту, що зберігається в об'єктній змінній базового типу, в об'єкт похідного класу називається знижуючим перетворенням (down-casting); зворотне перетворення називається таким, що підвищує (upcasting). Знижуюче перетворення вельми широко поширене, проте використовувати його не рекомендується, оскільки при цьому часто доводиться перевіряти фактичний тип об'єктної змінної в конструкціях наступного вигляду: If Typeof ouremployees(l) Is Programmer Then

    Else If Typeof ouremployees(l) Is Employee Then

    End If

    Перед вами ті самі конструкції, для боротьби з якими нам знадобився поліморфізм! (Перетворення, що підвищує, завжди обходиться без проблем, оскільки основоположне правило спадкоємства свідчить, що об'єкти похідних класів завжди можуть використовуватися замість об'єктів базових класів.)

    Хороший стиль програмування вимагає, щоб при використанні спеціальних засобів класу Programmer об'єкти зберігалися в контейнері, призначеному тільки для типу Programmer. В цьому випадку вам не доведеться перевіряти можливість перетворення командою If-typeof.

    Заміщення

    Термін «заміщення» (shadowing) зустрічався і в ранніх версіях VB, і в більшості мов програмування. Локальна змінна, ім'я якої збігається з ім'ям змінної, ширшою зоною видимості, що володіє, заміщає (приховує) цю змінну. До речі, це одна з причин, по якій змінним рівня модуля зазвичай привласнюються префікси m_, а глобальні змінні забезпечуються префіксами g_ — грамотний вибір імен допомагає уникнути помилок заміщення. Перевизначення успадкованого методу теж можна розглядати як свого роду заміщення. У VB .NET підтримується ще одна, надзвичайно могутній різновид заміщення:

    Член похідного класу, помічений ключовим словом Shadows (яке вперше з'явилося в бета-версиі 2), заміщає всі однойменні члени базового класу.

    За допомогою ключового слова Shadows можна визначити в похідному класі функцію, ім'я якої збігається з ім'ям процедури базового класу. З практичної точки зору ключове слово Shadows приводить до того, що в похідному класі з'являється абсолютно новий член із заданим ім'ям, внаслідок чого всі однойменні успадковані члени стають недоступними в похідному класі. З цього виходить, що успадковані члени класу з ключовим словом Shadows неможливо перевизначити, тому поліморфізм перестає працювати.

    За умовчанням VB .NET вирішує заміщення членів класів, але за відсутності клю-чевого слова Shadows видається попередження. Крім того, якщо один член класу оголошується з ключовим словом Shadows або Overloads, це ключове слово повинне використовуватися і для решти членів класу з тим же ім'ям.

    Іноді заміщення ускладнює ситуацію і приводить до виникнення нетривіальних помилок — наприклад, при поліморфному виклику заміщених методів і властивостей через об'єкт базового класу. Щоб розглянути ці проблеми на конкретному прикладі, ми внесемо деякі зміни до класу Programmer (нові рядки виділені жирним шрифтом):

    Public Class Programmer Inherits Employee Private m_gadget As String

    Private m_howtocallme As String = "Code guru "

    Public Sub Newcbyval thename As String, Byval cursalary As Decimal)

    Mybase.New(thename, cursalary)

    m_howtocal1me = m_howtocallme Sthename

    End Sub

    Public Overloads Overrides Sub Raisesalary(Byval Percent As Decimal)

    Mybase.RaiseSalary(1.2d * Percent, "special")

    End Sub

    Public Shadows Readonly Property Thename() As String

    Get

    Return mjtowtocallme

    End Get

    End Property

    End Class

    А зараз спробуйте запустити новий варіант процедури Sub Main:

    Sub Main()

    Dim torn As New Employee('Tom". 50000)

    Dim sally As New Programmer("Sally". 150000)

    Console.WriteLinetsally.TheName)

    Dim ouremployees(l) As Employee

    ouremployees(0)= tom

    ouremployees(l)= sally

    Dim anemployee As Employee

    For Each anemployee In ouremployees

    anemployee.RaiseSalary(0.lD)

    Console.WriteLinetanEmployee.TheName & "salary now is " &

    anemployee. Salary())

    Next

    Console. Readline()

    End Sub

    Мал. 5.3. Заміщення порушує роботу поліморфних викликів

    Результат показаний на мал. 5.3.

    Як видно з малюнка, поліморфний виклик перестав працювати. Перший рядок, виділений в Sub Main жирним шрифтом, правильно ставить перед ім'ям Sally титул «Code Guru». На жаль, в другому виділеному рядку поліморфізм вже не працює, унаслідок чого не викликається метод Thename похідного класу Programmer. Результат — ім'я виводиться без титулу. Іншими словами, при використанні ключового слова Shadows звернення до членів об'єктів здійснюються відповідно до типу контейнера, в якому зберігається об'єкт, а не їх фактичного типу (можна сказати, що при використанні ключового слова Shadows в похідному класі метод або властивість стає невіртуальним).

     




    :: Наша кнопка ::

    Отримати код:

    Підтримайте наш сайт і розмістіть нашу кнопку на своєму ресурсі.


    :: Реклама ::

    Скачати безкоштовно програму Microsoft Front Page 2003


    :: Посилання ::

    -


     

     

     


    Copyright ©