
- •Статичні методи.
- •Field identifier expected - очікується ідентифікатор поля.
- •Мал. 2 Схема обмеження виклику перевизначених статичних методів
- •Віртуальні методи і поліморфізм. Конструктор.
- •Procedure Met2; Virtual;
- •Object not initialized - об'єкт не ініціалізував.
- •Error 149: virtual expected - очікується слово virtual.
Object not initialized - об'єкт не ініціалізував.
Оскільки директива {$R+} уповільнює виконання програми, після відладки директиву треба видалити; за умовчанням працює директива {$R->.
У об'єкті може бути скільки завгодно конструкторів. Конструктор не може бути віртуальним. Конструктор може бути тільки статичним і може бути перевизначений. Конструктори успадковуються так само, як і інші статичні методи. З конструктора можна викликати і віртуальні методи.
|
|
|
Метод конструктора може бути і порожнім, оскільки основна інформація міститься не в тілі конструктора, а пов'язана з його заголовком, що містить слово Constructor. Наприклад: Constructor TA.TNIT ; Begin End;
Конструктору прийнято давати ім'я INIT. На практиці в якості конструктора який використовує метод, який встановлює деякі початкові значення екземпляра об'єкту. У конструкторі може відбуватися виділення ОП з купи, якщо поля даних динамічні, і необхідна ініціалізація полів даних (у тому числі і виклики конструкторів-предків для успадкованих полів). Приклад програми з використанням віртуальних методів даний в лістингу2. Це варіант програми лістингу 1, але з віртуальним методом Met2. |
||
|
|
Лістинг 2. Використання віртуальних методів.
Program virt1; {$F+,R+}
Uses Crt;
Type ObjName1 = object { - оголошення об'єкту-предка }
Fl1 : integer;
Constructor Met1; { - конструктор }
Procedure Met2; Virtual; { - віртуальний метод }
End;
ObjName2 = object(ObjName1) {- оголошення нащадка}
Procedure Met2; Virtual; { - віртуальний метод }
End;
{ Методи об'єкту Objname1 }
Constructor ObjName1.Met1;
Begin
Fl1 := 12;
Met2; { - виклик Met2 з конструктора }
End;
Procedure ObjNamel.Met2;
Begin
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, '2virt.res');
Rewrite (Output);
Writeln ('ОБ'ЄКТИ, ВІРТУАЛЬНІ МЕТОДИ');
Writeln ('Працюємо з VI - екземпляром типу предка');
V1.Met1; { - викликається конструктор Met1 для екземпляра VI - предка }
{ Met1 викликає метод Objname1.Met2 - предка }
V1.Met2; { - безпосередньо викликається метод Objname1.Met2; }
Writeln ('Працюємо з V2 - екземпляром типу нащадка');
V2.Met1; { - викликається конструктор Met1 для екземпляра V2 - нащадка VI; Met1 викликає метод Objname2.Met2 - нащадка -в цьому гідність віртуальних методів }
V2.Met2 { - безпосередньо викликається метод Objname2.Met2; }
Close. (Output) ;
End.
Кожен екземпляр об'єкту повинен ініціалізуватися окремим викликом конструктора. Не можна ініціалізувати один екземпляр об'єкту і потім привласнювати цей екземпляр іншим, неініціалізованим об'єктам. Інші екземпляри, навіть якщо вони містять правильні дані, не ініціалізують оператором привласнення і заблокують систему при будь-яких викликах їх віртуальних методів.
Наприклад:
Var Obj1, Obj2 : Tobj; { - оголошення змінних }
Begin
Obj1.Init; { - ініціалізація Obj1 }
Obj2 := Obj1; { - неприпустимо до ініціалізації Obj2 за допомогою Obj2.Init; }
End.
|
|
|
Хорошим стилем ООП є використання процедур ініціалізації предків. Тобто якщо нащадок має нову процедуру ініціалізації, то в ній зазвичай спочатку викликається процедура ініціалізації (наприклад, конструктор) безпосереднього предка, а потім виконується своя. Це природний спосіб проїніциалізіровать успадковані поля призначеним для цього методом. |
||
|
|
Додаткова можливість виклику методу, безпосередньо успадкованого об'єктом-нащадком, - використання ключового слова Inherited (успадкований) перед ім'ям методу, що викликається.
Наприклад, Obj1 безпосередній предок об'єкту Obj2. До складу Obj1 входить метод Met1. Виклик цього методу об'єкту Obj1 з методу Obj2.Met2 може бути заданий явно у вигляді:
Procedure Obj2.Met2;
Begin Inherited Met1 (A1, A2);
{ Це еквівалентно виклику: Obj1.Met1 (A1, A2); }
End;
При цьому не треба знати ім'я об'єкту-предка (Obj1). Основні правила використання віртуальних методів:
якщо тип об'єкту-предка описує метод як віртуальний, то всі його нащадки, які реалізують свій метод з тим же ім'ям, повинні описати цей метод як віртуальний. Не можна віртуальний метод замінити статичним. Інакше компілятор видасть повідомлення про помилку: