Статичні методи.
![]() | ![]() | |
Поліморфізм - це можливість мати декілька методів з одним і тим же ім'ям для різних об'єктів однієї ієрархії, тобто засіб для розвитку об'єктів в нащадках. Воно реалізується тим, що об'єкт-нащадок може перевизначати, тобто замінювати методи предка на нових з тими ж іменами. Який з методів виконуватиметься при зверненні до методу із заданим ім'ям, визначається типом об'єкту (предок або нащадок) і використовуваного методу. Методи об'єктів по способах їх перевизначення можуть бути статичні, віртуальні і динамічні (підклас віртуальних). Відповідно до цього процес установки взаємозв'язку об'єктів і методів може бути: § раннім - під час компіляції - для статичних методів; § пізнім - під час виконання програми (виклику методу) для віртуальних методів. Статичні методи: По замовчуванню всі методи статичні. Всі раніше розглянуті методи -статичні. Таке найменування методів пов'язане з тим, що визначення і розміщення посилань на них (для виклику методів) проводиться на етапі компіляції і на весь час виконання програми. Це – попереднє скріплення. | ||
![]() | ![]() | |
Список формальних параметрів статичних методів може бути різним у методу предка і методів нащадків, перевизначений (замінюючий) цей метод предка.
Із статичним методом пов'язаний спосіб спадкоємства. Якщо в оголошенні нащадка з'являється метод з тим же ім'ям, що і у предка, то в цьому типі і у всіх його нащадках цей метод буде перевизначений. Таким чином, нащадки можуть використовувати перевизначені ними методи предка. Предок може викликати тільки свої методи; методи нащадків для нього недоступні. Таким чином, при використанні статичних методів поліморфізм розповсюджується від поточного рівня ієрархії вниз, до нащадків.
Дії компілятора при обробці методів ієрархії об'єктів для статичних методів:
1) при виклику методу компілятор встановлює тип об'єкту, що викликає
метод;
2) потім він шукає метод в межах цього типу; знайшовши його, компілятор призначає виклик цього методу;
3) якщо метод не знайдений, то компілятор розглядає тип безпосереднього предка і шукає метод в його оголошенні:
a) якщо метод з таким ім'ям знайдений, формується виклик методу цього
предка;
b) якщо метод не знайдений в типі найближчого предка, компілятор переходить
до типу предка, наступного в ієрархії предків; і так до тих пір, поки
не буде знайдений викликаний метод;
c) якщо компілятор, дійшовши до верхнього рівня ієрархії, не знайде метод,
він видасть повідомлення про помилку номер 44 періоди компіляції:
Field identifier expected - очікується ідентифікатор поля.
Це повідомлення видається, якщо ідентифікатор не відповідає імені поля змінної типу RECORD або типу OBJECT.
![]() | ![]() | |
Істотне обмеження статичних методів: якщо метод предка викликає інші методи, то це можуть бути тільки методи предка, навіть якщо нащадок має свої власні методи з таким же ім'ям методу. Цей недолік зумовлений тим, що зв'язок об'єкту з методом проводився на етапі компіляції, статично, на весь час виконання програми. Цей недолік статичних методів усувається використанням віртуальних методів. Обмеження статичних методів розглянемо на прикладі лістингу програми. | ||
![]() | ![]() | |
Лістинг 1. Виклики статичних методів предка і нащадка.
Program novirt1;
Uses Crt;
Type ObjName1 = object { - оголошення об'єкту-предка }
Fl1 : integer; { - поле }
Procedure Met1; { - методи }
Procedure Met2;
End;
ObjName2 = object (ObjName1) { - оголошення нащадка }
Procedure Met2; { - заміна статичного методу }
End;
{ ------------ Методи об'єкту Objname1--------------------------------- }
Procedure ObjName1.Met1;
Begin Met2; { - виклик тільки методу Objname1.Met2!!}
End;
Procedure ObjName1.Met2;
Begin
FL1 := 12;
Writeln ('Працює метод ObjName1.Met2: FL1 = ', FL1)
End;
{ -------------- Метод об'єкту ObjName2 ------------------------------- }
Procedure ObjName2.Met2;
Begin
FL1 := 34;
Writeln ('Працює метод ObjName2.Met2: FL1 = ', FL1)
End;
Var
V1:ObjName1; { - змінна об'єктного типу - предка }
V2 : ObjName2; { - " " " нащадка }
{---------------- Основна програма ---------------------------------------}
Begin
ClrScr;
Assign (Output, 'Inovirt.res');
Rewrite (Output);
Writeln (‘ОБ'ЄКТИ, СТАТИЧНІ МЕТОДИ’ );
Writeln ('Працюємо з VI - екземпляром типу предка');
V1.Met1; {- викликається метод Met1 для екземпляра V1 - предка }
{ Met1 викликає метод Objname1.Met2 - предка }
V1.Met2; { - безпосередньо викликається метод Objname1.Met2; }
Writeln ('Працюємо з V2 - екземпляром типу нащадка');
V2.Met1; { - викликається метод Met1 для екземпляра V2 - нащадка; Met1 викликає метод Objname1.Met2 - предка, а не Objname2.Met2 - нащадка - в цьому - обмеження }
V2.Met2 { - безпосередньо викликається метод Objname2.Met2; }
Close (Output);
End.
Мал. 2 Схема обмеження виклику перевизначених статичних методів
![]() | ![]() | |
З нього видно істотне обмеження статичних методів: якщо метод (Met1 об'єкту Objname1) предка викликає інші методи (Met2), то це можуть бути тільки методи предка (objnamel .Met2), навіть якщо нащадок має свої власні методи з таким же ім'ям методу (objname2 .Met2). У прикладі лістингу оператор V2.Met1; викликає виконання методу Objnamel.Met1, який викликає метод Objnamel .Met2, не дивлячись на те що тип Objname2 має свій власний метод Objname2.Met2. Це відбувається тому що зв'язок об'єкту з методом проводився на етапі компіляції. Схематично це представлено на малюнку. | ||
![]() | ![]() | |