Тема 3 Об’єктно-орієнтоване програмування в Pascal. Віртуалізація методів 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Тема 3 Об’єктно-орієнтоване програмування в Pascal. Віртуалізація методів



 

Статичні методи

Проблема успадковування

Віртуалізація методів

Раннє і пізнє зв’язування

Підсумок

Питання по темі

 

 

Статичні методи

Попередньо описані методи об’єктів TStudent і TStudent1 називаються статичними. Така назва методів зв’язана з тим, що розміщення посилань на них здійснюється ще на етапі компіляції.

Обробка компілятором статичних методів схожа на обробку статичних змінних. Дії компілятора при обробці методів, що складають певну ієрархію, такі:

1. При виклику методу компілятор встановлює тип об’єкту, який викликав цей метод.

2. Встановивши тип, компілятор шукає метод у межах типу об’єкту. Знайшовши його, компілятор призначає виклик цього об’єкта.

3. Якщо вказаний метод не знайдений, то компілятор починає розглядати тип безпосереднього прабатька і шукає метод, ім’я якого викликано в межах цього прабатьківського типу. Якщо метод з таким іменем знайдений, виклик змінюється на виклик методу прабатька.

4. Якщо шуканий метод відсутній в типі найближчого прабатька, то компілятор переходить до типу наступного прабатька («діда») нашого типу, де й здійснюється подальший пошук. Процес продовжується до того часу, доки викликаний метод не буде знайдений, інакше компілятор, дійшовши до найостаннішого типу («родоначальника») і не знайшовши методу, ім’я якого викликається, видасть повідомлення про помилку компіляції номер 44 Field identifer expected (“Очікується ідентифікатор поля”). Це означає, що метод з таким іменем не визначений.

 

Звідси випливає одна важлива особливість. Якщо метод прабатька викликає інші методи, то останні також будуть методами прабатька, навіть якщо потомки мають свої власні методи. Це викликає так звану проблему успадковування, яку вдається розв’язати за рахунок віртуалізації методів.

 

Проблема успадковування

Дещо видозмінимо попередньо створені об’єкти TStudent і TStudent1 (Програма 3.1)

program prakt1;

uses crt;

type

TStudent=object

Name:String[30];

Date:string[10];

rate:real;

procedure init(nm,Dt:String;rt:real);

function GetName:string;

function getdate:string;

function getrate:real;

procedure showname;

procedure showdate;

procedure showrate;

end;

 

TStudent1=object(TStudent)

Bal:real;

procedure init(nm,dt:string;rt,bl:real);

function getname:string;

function getbal:real;

function getsum:real;

procedure showbal;

procedure showall;

end;

 

procedure TStudent.init(nm,dt:string;rt:real);

begin

name:=nm;

date:=dt;

rate:=rt;

end;

 

function TStudent.GetName:string;

begin

getname:=name;

end;

 

procedure TStudent.showname;

begin

writeln(getname);

end;

 

procedure TStudent1.init(nm,dt:string;rt,bl:real);

begin

TStudent.Init(nm,dt,rt);

bal:=bl;

end;

 

function TStudent1.GetName:string;

begin

getname:='~'+name+'~';

end;

 

 

(далі йде текст всіх раніше створених методів)

 

var st:TStudent;

st1:TStudent1;

begin

clrscr;

writeln('батьківський обєкт');

st.init('Ляшук','01.02.1995',700);

st.showname;

writeln('спадкоємець');

with st1 do begin

init('Panko','10.10.1995',550,4.8);

showname;

end;

writeln('=======================');

repeat until keypressed;

end.

Програма 3.1

Метод showname успадковується об’єктом TStudent1 від об’єкту TStudent.  В свою чергу, цей метод використовує інший: getname, який ми для TStudent і TStudent1 створили трохи по-різному:

function TStudent.GetName:string;

begin

getname:=name;

end;

 

function TStudent1.GetName:string;

begin

getname:='~'+name+'~';

end;

 

Але який варіант методу getname виконається, якщо ми застосуємо метод showname до змінної об’єктного типу TStudent1: власний метод цього типу чи відповідний метод батьківського типу? Склавши відповідну програму і виконавши її, переконаємося, що буде виконуватися метод батьківського типу.

Якщо ж нам потрібно, щоб виконався метод дочірнього типу, доведеться або його перевизначати, або ж вдатися до віртуалізації.

Віртуалізація методів

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

Метод стає віртуальним, якщо після його визначення в типі об’єкта проставлене службове слово VIRTUAL.

PROCEDURE ІмяМетоду(параметри); VIRTUAL;

 

або

FUNCTION ІмяМетоду(параметри):ТипЗначення; VIRTUAL;

При віртуалізації методів повинні виконуватися наступні умови:

1. Якщо прабатьківський тип об’єкту описує метод як віртуальний, то всі його похідні типи, що реалізують метод з таким самим іменем, повинен описувати цей тип теж як віртуальний. Іншими словами, не можна заміняти віртуальний метод статичним. Якщо ж це трапиться, компілятор повідомить про помилку номер 149 VIRTUAL expected (очікується службове слово VIRTUAL)

2. Якщо перевизначається реалізація віртуального методу, то заголовок заново визначеного віртуального методу у похідному типі не може бути зміненим. Інакше кажучи, повинні залишатися незмінними порядок розміщення, кількість і типи формальних параметрів в однойменних віртуальних методах. Якщо цей метод реалізується функцією, то не може мінятися і тип результату. При зміні заголовку методу компілятор видасть повідомлення про помилку номер 131 Header does not match previous definition («Заголовок не відповідає попередньом визначенню»).

3. В описі об’єкту повинен обов’язково описуватися спеціальний метод, що ініціалізує об’єкт (звичайно його називають Init). В цьому методі службове слово PROCEDURE в оголошенні і реалізації повинне бути замінене на слово CONSTRUCTOR. Конструктор завжди викликається до першого виклику віртуального методу. Виклик віртуального методу без попереднього виклику конструктора може привести систему до тупикового стану, а компілятор не перевіряє порядку виклику методів. Пам’ятаймо про це! Об’єкт може мати кілька конструкторів. Конструктор є статичним методом.

Спробує розв’язати проблему успадковування, поставлену у попередньому підрозділі, з використанням віртуалізації методів (Програма 3.2).

program prakt1;

uses crt;

type

TStudent=object

Name:String[30];

Date:string[10];

rate:real;

constructor init(nm,Dt:String;rt:real);

function GetName:string; virtual;

function getdate:string;

function getrate:real;

procedure showname;

procedure showdate;

procedure showrate;

end;

 

TStudent1=object(TStudent)

Bal:real;

constructor init(nm,dt:string;rt,bl:real);

function getname:string;virtual;

function getbal:real;

function getsum:real;

procedure showbal;

procedure showall;

end;

 

constructor TStudent.init(nm,dt:string;rt:real);

begin

name:=nm;

date:=dt;

rate:=rt;

end;

 

function TStudent.GetName:string;

begin

getname:=name;

end;

 

 

procedure TStudent.showname;

begin

writeln(getname);

end;

 

 

constructor TStudent1.init(nm,dt:string;rt,bl:real);

begin

name:=nm;

date:=dt;

rate:=rt;

bal:=bl;

end;

 

function TStudent1.GetName:string;

begin

getname:=’~’+name+’~’;

end;

 

(далі йде текст всіх раніше створених методів)

 

 

var st:TStudent;

st1:TStudent1;

begin

clrscr;

writeln(‘батьківський обєкт’);

st.init(‘Ляшук’,’01.02.1995’,700);

st.showname;

writeln(‘спадкоємець’);

with st1 do begin

init(‘Panko’,’10.10.1995’,550,4.8);

showname;

end;

writeln(‘=======================’);

repeat until keypressed;

end.

Програма 3.2

Метод getname ми описали як віртуальний і це дало нам змогу по-справжньом використати поліморфізм. Виконавши програму, переконаємося, що поле name батьківського і дочірнього об’єкту виводяться дещо по-різному:

Раннє і пізнє зв’язування

Різниця між викликом статичного і динамічного (віртуального) методу полягає в тому, що у першому випадку компілятору зарані відомий зв’язок об’єкта з методом і він встановлює його на етапі компіляції. У другому – компілятор нібито відкладає розв’язок до моменту виконання програми.

Якщо використовувати раніше створений приклад у «статичному» варіанті, то виклик процедури getname міг привести тільки до виконання найближчого в об’єктній ієрархії getsum, тобто TStudent.getname. Якщо припустити, що власний метод дочірнього типу, котрий би перевизначав TStudent.showname, не існує, то будь-який породжений по відношенню до TStudent тип буде працювати саме з тим showname, котрий визначений у батьківському типі і, відповідно, з тим самим getname, котрий визначений у батьківському типі. Рішення про це приймається на етапі компіляції, а таке зв’язування називається раннім зв’язуванням.

Якщо ж ми використовуємо віртуалізацію методів, то все відбувається інакше. Кожен тип об’єктів має власний метод getname, тому від того, який екземпляр викликає метод showname, залежить, який саме getname виконається. Тому рішення про виклик методу getname всередині showname доводиться відкласти, його неможливо прийняти при компіляції коду showname. Інформація про те, об’єкт якого типу викликав showname, недоступна під час компіляції, тому розв’язок відкладається до моменту, поки програма не почне виконуватися і поки не можна буде встановити, об’єкт якого типу викликав цей метод. Таке зв’язування називається пізнім.

Підсумок

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

Методом розв’язку проблеми успадкування є віртуалізація методів, яка дає нам змогу по-справжньому використовувати поліморфізм: той сам метод може працювати по-різному в залежності від того, який об’єкт його викликає. Зв’язування об’єкту з методом на етапі компіляції називається раннім, на етапі виконання – пізнім.

Якщо об’єкт має віртуальний метод, то один з методів цього об’єкту, який його ініціалізує, повинен бути описаний як конструктор.

 


Питання по темі

1. Якщо метод описаний без жодних спеціальних уточнень, то він є

а) статичним

б) віртуальним

г) це залежить від того, який об’єкт його викликає.

 

2. Вкажіть правильний опис віртуального методу

а) constructor init(nm,dt:string;rt,bl:real);

б) function getname:string;virtual;

в) function getbal:real;

 

3. Якщо метод працює по-різному в залежності від того, екземпляр якого типу його викликає, то це називається:

а) інкапсуляцією

б) успадковуванням

в) поліморфізмом

 

4. Нехай об’єкт B є батьківським по відношенню до D. Один з типів об’єкту В з іменем М є віртуальним, об’єкт D його перевизначає. Виберіть з описів цього методу правильний

а) procedure B.M(a:string); virtual;

procedure D.M(a:string);

 

б) procedure B.M(a:string); virtual;

procedure D.M(a:string;l:integer); virtual

 

в) procedure B.M(a:string); virtual;

 procedure D.M(a:string); virtual;

 

5. Якщо об’єкт містить хоч один віртуальний метод, то один з його методів повинен бути описаний як

 


Тема 4 Об’єктно-орієнтоване програмування в Pascal. Таблиця віртуальних методів. Переваги і недоліки віртуальних методів.

 

Конструктори і таблиця віртуальних методів

Відлагодження програм з використанням віртуальних методів

Розширюваність об’єктів

Переваги і недоліки віртуальних методів

 

Конструктори і таблиця віртуальних методів

Кожний екземпляр (змінна) типу «об’єкт», що містить віртуальні методи, повинен ініціалізуватися окремим викликом конструктора. Якщо змінна А ініціалізована викликом конструктора, а змінна В того ж типу не ініціалізована, то присвоювання В:=А не ініціалізує змінну В і при виклику її віртуальних методів програма може зависнути.

Щоб зрозуміти, що робить конструктор, розберемося в механізмі реалізації віртуальних методів. Кожен об’єктний тип (саме тип, а не екземпляр) має «таблицю віртуальних методів» (VMT), яка містить розмір типу об’єкту і адреси кодів процедур чи функцій, що реалізують кожен з його віртуальних методів. При виклику віртуального методу яким-небудь екземпляром розміщення коду реалізації цього методу визначається за таблицею VMT для типу цього екземпляра. Конструктор встановлює зв’язок між екземпляром, який викликає цей конструктор, і таблицею віртуальних методів даного об’єктного типу. Якщо ж конструктор не буде викликаний до звертання до віртуального методу, то перед комп’ютером постане питання, де шукати цей метод. Це і призведе до тупикової ситуації.

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

При передачі в процедуру чи функцію поліморфного об’єкту, що має віртуальні методи, адреси цих методів передаються через таблицю VMT, що відповідає цьому об’єкту. Це гарантує, що спрацюють саме ті методи, які малися на увазі при оголошенні тапу об’єкта. Крім того, якщо об’єкт Z успадковує від об’єкту Y віртуальний метод, що викликає інші методи, то ці останні виклики будуть відноситися до методів об’єкту Z, а не Y. У випадку статичних методів все було б навпаки (виклики «не повернулись» би в Y).

 



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 49; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.149.26.176 (0.055 с.)