Лекція 18 Динамічні об'єкти



Скачати 61.52 Kb.
Дата конвертації04.12.2016
Розмір61.52 Kb.
ЛЕКЦІЯ 18
Динамічні об'єкти
Як вказувалося в попередній лекції, описавши клас, ми можемо оголошувати змінні цього класу, розміщуючи їх як в статичній, так і динамічній пам'яті. Для оголошення динамічного об'єкту використовують покажчики на об'єкти класу, що описуються таким чином:
Var <ім'я покажчика> : <ім’я класу>;
Для розміщення об'єкту в динамічній пам'яті використовують процедуру або функцію New:

процедура



New (<ім'я покажчика>);

функція


<ім'я покажчика>:= New (<тип «покажчик на клас»>).
Якщо динамічний об'єкт використовує віртуальні методи класу, то до звернення до цих методів він повинен викликати конструктор :

<ім'я покажчика> ^ .<ім’я конструктора>(<список параметрів>).

У Borland Pascal 7.0 є можливість використання розширеного варіанту процедури і функції New, який дозволяє в одній операції

виділити пам'ять під об'єкт і викликати конструктор:

процедура



New (<і’мя покажчика>

<ім'я конструктора>(<список параметрів>));

функція


<ім'я покажчика>: = New (<тип «покажчик на класс»>

<ім'я конструктора>(<список параметрів>))
Такий варіант процедури або функції New працює таким чином. Спочатку здійснюється спроба виділити пам'ять під об'єкт, а потім викликається конструктор.

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


Dispose (<ім'я покажчика>);
Якщо клас об'єкту включає віртуальні методи, то при знищенні об'єкту обов'язково повинні викликатися спеціальний метод - деструкція.

Так само, як для конструктора, для деструкції службове слово Procedure повинне замінюватися службовим словом, Destructor, що має на увазі виконання деяких спеціальних дій при знищенні об'єкту: деструкцію визначає реальний розмір об'єкту і передає його процедурі Dispose. Якщо конструктор рекомендується називати Init, то деструкцію зазвичай називають Done. Деструкції можуть успадковуватися, бути статичними або віртуальними. Зазвичай вони використовуються для звільнення пам'яті, виділеної під динамічні поля об'єкту.

Деструкцію можна викликати в розширеному форматі процедури Dispose:
Dispose (<ім'я указателя>,<имя деструкції>);
Для динамічних об'єктів має сенс оголошувати зарезервовану віртуальну деструкцію, нехай навіть і порожню:
Destructor <ім'я класу> . Done; virtual;

Begin End;
Контроль розподілу пам'яті. Якщо пам'яті для розміщення динамічного об'єкту або динамічних полів опиниться недостатньо, то виклик процедури або функції New приведе до виникнення помилки часу виконання з номером 203 ( «переповнювання динамічної пам'яті»).

При виявленні браку пам'яті процедура або функція New поверне покажчик із значенням nil, що можна перевірити в програмі.

Якщо таку ситуацію виявляє конструктор при розподілі пам'яті для розміщення динамічних полів, то доцільно, щоб він відмінив всі вже виконані розподіли пам'яті. Для цього введена стандартна процедура Fail без параметрів. Процедура Fail може бути викликана тільки з конструктора. Вона відміняє вже виконані призначення пам'яті і повертає значення nil як адресу об'єкту.
Створення бібліотек класів

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

У разі, коли модуль У використовує модуль А, модуль В може визначати похідні класи від будь-якого класу, що експортується модулем А.

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

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

За допомогою стандартної директиви private можна оголосити частину полів і методів прихованими від користувачів модуля. Вони будуть доступні тільки усередині модуля, де оголошений клас.

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

Щоб опис класу зробити гнучкішим, використовують директиву public. Дана директива робить поля і методи класу загальнодоступними поза модулем.

Структура модуля з описом класу і об'єктів, що експортуються, виглядає таким чином:

Unit <ім'я модуля>;

Interface { інтерфейсний розділ}

Турі

<ім'я класу> = object

private <приховані поля>;

public <достуні поля>;

private < приховані методи>;

public <доступні методи>;

End;

Var <оголошення об'єктів класу, що експортуються>

Implementation { розділ реалізації}

{ реалізація методів}



Begin { розділ ініціалізації}

{ виклики конструкторів об'єктів, що експортуються}



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

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

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

Borland Pascal 7.0 надає можливість використання в класах об'єктних полів. Розглянемо це на прикладі.

Приклад. Використання об'єктних полів.

Розглянемо програму, в якій клас рядок (OUTS), що виводиться, оголошений як частина класу Вікно (Win). Це реалізовано включенням в структуру класу Win об'єктного поля Ob_Field.


Program Demo;

Uses crt;

Турі Outs = Object { клас рядок, що Виводиться}

S : String { рядок виводу}

Cs : byte; { колір символів рядка}

Procedure Init(Sn : String; Csn : byte); {ініціалізація полів}

Procedure Print; {виведення рядка}

End;


Procedure Outs. Init; Begin S := Sn; Cs:= Csn; End;

Procedure Outs. Print; Begin TextColor(Cs); Write(S);End;

Турі

Win = Object {клас Вікно}



XI, У1,х2, У2 {координати вікна}

Сf : byte; {колір фону}

Ob_Field { статичне об'єктне поле}

Procedure Init (Хп1, Yп1, Хп2, Yп2, Сfn : byte; Obn :OutS);

Procedure MakeWin; { зображення вікна}

End;


Procedure Win.Init; Begin Х1:=хп1;Y1:=Yп1; Х2:=хп2; Y2:=Yп2; Сf:=сfп;

Ob_Field:= Оbn; { ініціалізація об'єктного поля}

End;

Procedure Win.MakeWin;



Begin

Window(Х1,y1,х2,y2); Textbackrgound(Cf); Clrscr;

Ob_Field.Print;{ звернення до методу Print класу OUTS як до методу поля

класу Win}

End;

Var ; { оголошення екземплярів класів}



V : Win; F : OUTS;

Begin


F.Init{ 'Об'єктне поле',1); { ініціалізувати об'єкти}

V.Init(20,10,35,10,F); {F - параметр-об'єкт}

V.MakeWin; { зобразити вікна і вивести рядок}

Readkey;


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


База даних захищена авторським правом ©lecture.in.ua 2016
звернутися до адміністрації

    Головна сторінка