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



ЗНАЕТЕ ЛИ ВЫ?

Function HeapFunc ( Size : Word ): Integer ; Far

Поиск

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

Нова функція обробки помилок встановлюється шляхом присвоювання її адреси змінній HeapError таким способом:

HeapError:=@ HeapFunc

Така можливість може виявитися корисною при використанні конструкторів.

За замовчуванням, якщо не вистачає пам’яті для розміщення екземпляру динамічного об’єкту, то виклик конструктора, який використовує розширений синтаксис процедури New, генерує фатальну помилку виконання з кодом 203. Якщо встановлюється функція користувача обробки помилок динамічної пам’яті, яка повертає 1, а не стандартний результат 0, то виклик конструктора через New буде повертати Nil в тому випадку, якщо конструктор не зможе завершити запит (замість припинення роботи програми).

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

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

Якщо динамічні екземпляри розміщуються за допомогою розширеного синтаксису New, то результуюче значення Nil, що передається вказівнику, свідчить про невдалу операцію. Але не існує таких змінних типу вказівник, які можна було б перевірити після створення статичного екземпляру чи після виклику успадкованого конструктора. Замість цього Pascal в якості функцій дозволяє використовувати конструктори, що повертають результат типу BOOLEAN. Повернуте значення TRUE означає успіх, а FALSE – невдачу завдяки виклику Fail всередині конструктора.

Розглянемо, як можна описати послідовний виклик конструкторів типу TStudent і TStudent1. Досі вони не давали можливості визначати помилки:

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

begin

name:=nm;

date:=dt;

rate:=rt;

end;

 

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

begin

TStudent.Init(nm,dt,rt);

bal:=bl;

end;

 

При такому описі, якщо ініціалізується екземпляр дочірнього типу TStudent1, то він викликає конструктор типу TStudent. Якщо при виклику цього останнього трапиться помилка, доведеться відмінити і виклик першого конструктора.

От як можна переписати конструктор TStudent1.init з врахуванням виявлення помилок:

 

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

Begin

IF NOT TStudent.Init(nm,dt,rt) THEN Failed;

bal:=bl;

end;

Function HeapFunc(Size:Word):Integer;Far;

Begin

HeapFunc:=1;

End;

 

Зверніть увагу, що функція HeapFunc виконує єдину операцію: при будь-якому виклику повертає 1. Виконувати інші операції в даному випадку немає потреби.

 

Ключове слово INHERITED

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

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

Begin

IF NOT TStudent.Init(nm,dt,rt) THEN Failed;

bal:=bl;

end;

 

Pascal дає можливість використовувати спеціальне слово INHERITED, використовуючи яке можна викликати методи предка без вказання імені предка.

 

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

Begin

IF NOT INHERITED Init(nm,dt,rt) THEN Failed;

bal:= bl;

end;

 

Це може виявитися корисним при використанні великої ієрархії об’єктів, коли складно запам’ятати всі зв’язки типу «предок-потомок».

 

Деструктори

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

 

Dispose (S);

 

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

Student. Done;

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

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

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

Type

TStudent = object

Name:String[30];

Date:string[10];

rate:real;

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

Destructor done; virtual;

function GetName:string; virtual;

function getdate:string;

function getrate:real;

procedure showname;

procedure showdate;

procedure showrate;

end;

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

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

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

Очевидно, що розміри типів об’єктів відрізняються. Інформація про розмір об’єкта, який видаляється, стає доступною для деструктора в момент видалення завдяки вертанню до таблиці віртуальних методів екземплярів об’єктів певного типу VMT.

Для виконання звільнення пам’яті при пізньому зв’язуванні деструктор потрібно викликати як частину розширеного синтаксису процедури Dispose

Dispose(S,Done);

Деструктор об’єкту, на який вказує S, виконується як звичайний метод. Однак, як тільки остання дія буде виконана, деструктор почне шукати розмір екземпляра вказаного типу у VMT і передасть його розмір процедурі Dispose. Процедура Dispose завершує процес шляхом видалення правильного числа байтів області динамічної пам’яті, яка відносилася до S^. Число звільнюваних байтів буде правильним незалежно від того, чи вказує S на екземпляр батьківського (TStudent) чи дочірнього (TStudent1) типу. Тому деструктор рекомендується робити віртуальним навіть якщо ніяких віртуальних методів об’єкт не містить.

Виклик деструктора поза процедурою Dispose не приведе до автоматичного вивільнення пам’яті.

Необхідно відмітити, що сам по собі метод деструктора може бути порожнім і виконувати лише функцію зв’язку з процедурою Dispose

 

Destructor TStudent. Done;

Begin

end;

 

оскільки основна інформація міститься не в тілі деструктора, а зв’язана з його заголовком, що містить слово Destructor

Деструктор дочірнього типу TStudent1 теж теж повинен останньою дією викликати відповідний деструктор свого безпосереднього предка, щоб звільнити поля всіх успадкованих вказівників об’єкту

 

Destructor TStudent1.Done;

Begin

Inherited Done;

end;

Підсумок

Об’єкти, як і звичайні змінні, можуть бути динамічними. Новий динамічний об’єкт створюється оператором New, цей оператор має також розширений синтаксис і може водночас зі створенням об’єктної змінної здійснювати її ініціалізацію. Для виявлення помилок конструктора використовується функція HeapFunc такого формату

Function HeapFunc(Size: Word): Integer; Far

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

 

 

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

1. Нехай Т – змінна типу «вказівник на об’єкт». Який запис оператора New буде правильним?

а) New(T)

б) New(^T)

в) New(T^)

 

2. Як би виглядав розширений синтаксис попереднього оператора за умови, що виклик конструктора Init правильний?

а)New(Init(70,90,120,Т);

б)New(Т, Init(70,90,120);

в)New(Т^, Init(70,90,120);

 

3. Виклик якої процедури змушує конструктор видалити динамічний екземпляр, що був розміщений при вході в конструктор

а) Fail

б) Delete

в) Refuge

 

4. Яке ключове слово свідчить про те, що викликається метод предка даного об’єкта?

а) Inherited

б) Ancestor

в) Testament

 

5. Яка стандартна назва деструктора в TurboPascal?

а) Delete

б) Backup

в) Done


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

 

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

Внутрішнє представлення об’єктів

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

Функції роботи з таблицею віртуальних методів

Таблиця динамічних методів

Виклик статичних методів

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

Виклик динамічних методів

Виклик конструкторів та деструкторів

Підсумок

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

 

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

В Pascal-і існує додатковий клас методів пізнього зв’язування, які називаються динамічними. Фактично, динамічні методи є підкласом віртуальних методів і відрізняються від них тільки способом виклику на етапі виконання. У всьому іншому динамічний метод можна розглядати як еквівалентний віртуальному.

Опис динамічного методу аналогічний опису віртуального методу, за винятком того, що він повинен включати в себе індекс динамічного методу, який вказується відразу після ключового слова VIRTUAL. Індекс динамічного методу повинен задаватися цілочисельною константою в діапазоні значень від 1 до 65535 і являти собою унікальне значення серед індексів інших динамічних методів, що містяться в об’єктному типі чи його предках. Наприклад

FUNCTION GetName:String;VIRTUAL 5;

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

Використання динамічних методів доцільне при створенні довгої ієрархії об’єктів з великою кількістю віртуальних методів. Для цих останніх в ієрархії будуть створюватися дуже довгі таблиці віртуальних методів з вказуванням всіх віртуальних методів предків, хоча перевизначатися може тільки частина з них. Це вимагає значного об’єму використовуваної пам’яті для зберігання VMT.

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

 



Поделиться:


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

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