Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Віртуальні методи і поліморфізм. Конструктор




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

Віртуальний (що здається, гіпотетичний) метод має специфікатор (стандартну директиву) Virtual.

Наприклад:

Procedure Met2; Virtual;

Віртуальний метод призначений для перевизначення віртуального методу попереднього предка. Неприпустимо змішування статичних і віртуальних методів при їх перевизначені.

Обмеження: перевизначені віртуальні методи повинні мати такий самий набір формальних параметрів, як і найперший віртуальний метод багаторівневої ієрархії об'єктів.

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

Відповідно до цього основні відмінності перевизначення віртуальних методів від перевизначення статичних методів полягають в наступному:

1) якщо для екземпляра нащадка методи предка викликають інші віртуальні
методи, імена яких є в об'єкті-предку і в об'єкті-нащадку, то визиваються методи нащадка;

2) віртуальні методи використовують пізнє пов'язання даних з методами,
за допомогою яких вони оброблятимуться, тобто скріплення на етапі
виконання програми.

Компілятор не встановлює зв'язку об'єкту з віртуальним методом. Замість цього він створює спеціальну таблицю віртуальних методів (ТВМ, VMT -virtual Method Table). Для кожного типу об'єкту створюється своя ТВМ; кожен екземпляр об'єкту використовує цю ТВМ, єдину для даного типу віртуальних об'єктів. У кожній ТВМ міститься розмір даного типу об'єкту в байтах. ТВМ будь-якого об'єкту доступна через прихований параметр Self, що містить адресу ТВМ, яка передається методу при виклику.

Скріплення кожного екземпляра об'єкту і його ТВМ здійснюється за допомогою конструктора на етапі виконання програми. Це спеціальний метод, подібний до звичайної процедури, але в заголовку замість PROCEDURE міститься слово CONSTRUCTOR.

Чим реально конструктор відрізняється від звичайного методу? Конструктор, крім описаних в ньому дій, встановлює зв'язок між об’єктом і спеціальною таблицею віртуальних методів, які зберігають адреса кодів, котрі реалізують віртуальні методи.
     

Якщо об'єктний тип містить віртуальний метод, то він повинен містити хоч би один конструктор. Кожен екземпляр об'єкту повинен ініціалізуватися окремим викликом конструктора. Конструктор ініціалізував екземпляр об'єкту і встановлює для нього значення адреси його ТВМ. Екземпляр об'єкту містить тільки адресу ТВМ, а не саму ТВМ.

Виклик конструктора повинен передувати виклику будь-якого віртуального методу для обробки даного екземпляра об'єкту. Звернення до віртуального методу до виклику конструктора викличе помилку на етапі виконання програми, оскільки немає зв'язку екземпляра об'єкту з його ТВМ.

При відладці програми можна використовувати директиву компілятора {$R+}. При цьому компілятор перевірятиме, чи ініціалізував екземпляр об'єкт, що викликає віртуальний метод. Якщо в процесі перевірки ініціалізації екземпляра об'єкту, що викликає віртуальний метод, буде виявлений виклик методу до ініціалізації об'єкту конструктором, видається повідомлення про фатальну помилку 210:

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). Основні правила використання віртуальних методів:

1) якщо тип об'єкту-предка описує метод як віртуальний, то всі його нащадки, які реалізують свій метод з тим же ім'ям, повинні описати
цей метод як віртуальний. Не можна віртуальний метод замінити статичним. Інакше компілятор видасть повідомлення про помилку:

Error 149: VIRTUAL expected - ОЧІКУЄТЬСЯ СЛОВО VIRTUAL.

2) якщо перевизначається віртуальний метод, то заголовок перевизначуваного
методу не може бути змінений; повинні залишитися незмінними: кількість, послідовність і типи формальних параметрів в однойменних
віртуальних методах. Якщо цей метод - функція, то не повинен змінюватися і тип результату. При порушенні цього правила компілятор видасть повідомлення:

131: Header does not match previous definition - заголовок не відповідає попередньому визначенню;

3) у описі об'єкту, що має віртуальні методи, обов'язковий - конструктор. Він встановлює роботу механізму віртуальних методів. Виклик віртуального методу без попереднього виклику конструктора може привести до тупикового стану. Щоб уникнути цього, на період відладки треба включити директиву компілятора {$R+};

4) кожен екземпляр об'єкту повинен ініціалізуватися окремим викликом конструктора;

5) кількість конструкторів може бути будь-яким;

6) конструктор повинен бути статичним і може бути перевизначений.

 




Поделиться с друзьями:


Дата добавления: 2014-01-04; Просмотров: 720; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.026 сек.