З предмету «Об’єктно орієнтоване програмування» 


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



ЗНАЕТЕ ЛИ ВЫ?

З предмету «Об’єктно орієнтоване програмування»



Курс лекцій

З предмету «Об’єктно орієнтоване програмування»

 

Частина 1 – «Об’єктно орієнтоване програмування в мові Паскаль»

 

 


Зміст

 

Вступ. Загальний опис об’єктно-орієнтованого програмування

Тема 1 Об’єктно-орієнтоване програмування в Pascal. Означення об’єкту, його поля і методи.

Тема 2 Об’єктно-орієнтоване програмування в Pascal. Успадковування. Інкапсуляція

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

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

Тема 5. Об’єктно-орієнтоване програмування в Pascal. Вказівники і динамічна пам’ять

Тема 6 Об’єктно-орієнтоване програмування в Pascal. Вказівники, динамічна пам’ять та об’єкти

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

Тема 8 Об’єктно-орієнтоване програмування в Delphi

 


 

Вступ. Загальний опис об’єктно-орієнтованого програмування

Структурне програмування

Процедурні мови

Недоліки структурного програмування

Неконтрольований доступ до даних

Моделювання реального світу

Об’єктно орієнтований підхід

Характеристики об’єктно орієнтованих мов

Об’єкти

Класи

Успадковування

Повторне використання коду

Типи даних користувача

Поліморфізм і перезавантаження

Підсумок

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

 

 

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

Структурне програмування

Процедурні мови

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

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

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

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

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

 

Моделювання реального світу

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

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

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

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

Об’єкти

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

Що повинне представлятися в програмі у вигляду об’єктів? Це залежить від типу задачі і уяви розробника. Можливі такі варіанти:

Ø Фізичні об’єкти

· Автомобілі при моделюванні вуличного руху

· Елементи схеми при моделюванні електромережі

· Країни при створенні економічної моделі

· Літаки при моделюванні диспетчерської системи

 

Ø Елементи інтерфейсу

· Вікна

· Кнопки

· Меню

· Випадаючі списки

· Поля введення і поля редагування

· Графічні об’єкти (лінії, прямокутники, круги)

· Миша, клавіатура, дискові пристрої, принтери

 

Ø Структури даних

· Масиви

· Стеки

· Черги

· Дерева

· Зв’язані списки

 

Ø Групи людей

· Співробітники

· Студенти

· Покупці

· Продавці

 

Ø Сховища даних

· Інвентарні описи

· Перелік номенклатур

· Списки співробітників

· Словники

 

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

 

Класи

Коли ми говоримо про об’єкти, то кажемо, що вони є екземплярами класів. Розглянемо таку аналогію. Практично всі комп’ютерні мови мають стандартні типи даних, у мові С є цілий тип int. Ми можемо визначити змінні таких типів у наших програмах:

int day;

int divisor;

int n;

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

 

Рисунок 3. Клас і його об’єкти

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

 

Успадковування

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

Принципи, покладені в основу такого поділу, полягають в тому, що кожен підклас володіє властивостями, притаманними тому класу, з якого виділений даний підклас: студенти всіх відділень є і студентами технікуму. Крім тих властивостей, які є спільними у даного класу і підкласу, підклас може мати і власні властивості: студенти-програмісти навчаються 4 роки, студенти-статистики – 3 роки. Ілюстрація цієї ідеї приведена на рисунку 4.

Рисунок 4 Успадковування

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

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

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

 

Повторне використання коду

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

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

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

Легкість повторного використання коду вже написаних програм є важливою перевагою ООП.

 

Типи даних користувача

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

position1=position2+origin

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

 

Підсумок

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

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

 


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

1. Мови Pascal, Basic i C є ___________ мовами, а С++ _________ мовою

2. В якості зразка по відношенню до об’єкту виступає:

а) метод

б) клас

в) операція

г) значення

3. Двома основними компонентами об’єкту є ____________ і функції, які з ними працюють

4. Функцію, що входить до складу класу, називають

а) функція-член класу

б) оператор класу

в) функція класу

г) метод класу

5. Захист даних від несанкціонованого доступу іншими функціями називається

6. Які з перелічених далі причин є головними для використання об’єктно-орієнтованих мов?

а) можливість створення власних типів даних

б) простота операторів об’єктно-орієнтованих мов порівняно з процедурними мовами

в) наявність засобів для автокорекції помилок в об’єктно-орієнтованих мовах

г) об’єктно-орієнтовані програми легше концептуалізуються

7. __________ відображають об’єкти реального світу точніше, ніж функції

8. Об’єднання даних і функцій називається

9. Можливість виконання оператором чи функцією різних дій залежно від типу операндів називається

10. Операція, що виконує задані дії над користувацьким типом даних, називається:

а) поліморфічною

б) інкапсульованою

в) класифікованою

г) перезавантаженою

 


Var

Student:TStudent;

або так

TYPE

PStudent=^TStudent;

VAR

Stat_st:TStudent;

Dyn_St:PStudent;

Перед використанням змінної Dyn_St необхідно виділити для неї пам’ять з допомогою функції New.

Поля об’єкта

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

Student.Rate:=800;

WITH Student DO BEGIN

Name:=’Лящук Петро Павлович’;

Date:=’25.06.1995’;

END;

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

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

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

 

Методи

Ініціалізація полів об’єкта

Звичайно при роботі з записами виникає проблема ініціалізації полів запису. Припустимо, наявна така структура

TStudent=OBJECT

  Name:String[30];

  Date:String[10];

  Rate:Real;

END;

Початківці часто використовують оператор WITH для присвоєння полям Name, Date i Rate початкових значень

VAR

Student:TStudent;

WITH Student DO BEGIN

Name:=’Лящук Петро Павлович’;

Date:=’25.06.1995’;

Rate:=700;

END;

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

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

Type

TStudent=OBJECT

  Name:String[30];

  Date:String[10];

  Rate:Real;

  Procedure Init(Nm,Dt:String; RT:Real);

END;

Begin

Name:=Nm;

Date:=Dt;

Rate:=Rt;

End;

Тепер для ініціалізації екземпляра типу TStudent достатньо просто викликати його метод

VAR

Student:TStudent;

Student.Init(‘Лящук Петро Павлович’,’25.06.1995’,700);

 

Визначення методів

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

Type

TStudent=OBJECT

  Name:String[30];

  Date:String[10];

  Rate:Real;

  Procedure Init(Nm,Dt:String; RT:Real);

  Function GetName:String;

  Function Get Date:String;

  Function Get Rate: Real;

END;

Зауважимо, що поля даних повинні бути оголошені перед оголошенням методу.

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

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

 

Begin

Name:=Nm;

Date:=Dt;

Rate:=Rt;

End;

 

Function TStudent.GetName:String;

Begin

GetName:=Name;

End;

Function TStudent.GetDate:String;

Begin

GetDate:=Date;

End;

Function TStudent.GetRate:String;

Begin

GetRate:=Rate;

End;

 

Всередині визначення методу його ім’я вже не зв’язується з типом TStudent.

 

Begin

GetName:=Self.Name;

End;

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

Звичайно нема необхідності у використанні цього параметра, оскільки генерований Pascal-ем код обробляє його автоматично. Однак у деяких ситуаціях, коли, наприклад, об’єкти різних типів мають поля зі співпадаючими іменами або треба звернутися до об’єкту в цілому (взяти його адресу, порівняти його з іншим об’єктом цього ж типу), можна використовувати параметр Self явно. (Ми це будемо робити в Лабораторній роботі 1-2).

 

Підсумок

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

WITH Self DO метод;

що дає змогу звертатися до полів об’єкта без додаткових кваліфікаторів.

 

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

1. Компоненти-дані називаються ________ об’єкта, а компоненти-процедури і функції називаються _____________

2. Назвати ключове слово для позначення типу «об’єкт»

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

4. Які складові частини програми можуть звертатися до полів об’єкта по імені

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

 

 


 Тема 2 Об’єктно-орієнтоване програмування в Pascal. Успадковування. Інкапсуляція

 

Успадкування

Присвоювання об’єктів

Приховування даних в об’єктах

Інкапсуляція

Перевизначення методів

Підсумок

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

 

Успадкування

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

Назвемо новий тип TStudent1. Звичайно, ми могли б визначити його, просто продублювавши відповідний опис типу TStudent і додавши нове поле даних. Вийшло б щось таке:

TStudent1 =OBJECT

  Name:String[30];

  Date:String[10];

  Rate:Real;

  Bal: Real;

END;

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

TStudent1= OBJECT(TStudent)

  Bal: Real;

END;

Тип TStudent називається батьківським (parent), тип TStudent1 – дочірнім (child). Фактично цей процес можна продовжувати як завгодно довго: можемо визначити наступний тип, для якого TStudent1 буде батьківським. Найчастіше побудова об’єктно-орієнтованих прикладних програм полягає в побудові такої ієрархії об’єктів.

Всі типи, які успадковують тип TStudent, називаються його дочірніми типами, але TStudent1 є безпосереднім дочірнім типом від TStudent, а TStudent є безпосереднім породжуючим типом для TStudent1.

 

Присвоювання об’єктів

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

VAR

St: Tstudent;

St 1: Tstudent 1;

то для копіювання значення, записаного у змінній St1, у змінну St2 достатньо виконати присвоювання

St:= St1;

Подібна операція заповнить поля даних у St значеннями аналогічних полів, успадкованих St1 (тобто полів Name, Date, Rate). Методи таким способом не присвоюються. Оскільки похідний тип завжди має не менше полів даних, ніж прабатьківський, операція можлива саме у такий спосіб:

Прабатько:=Спадкоємець;

При цьому гарантується заповнення всіх полів змінної, що стоїть зліва. Інакше виникла б невизначеність із «зайвими» полями, присутніми у правій змінній. Щоб уникнути такої невизначеності, забороно ставити «породжений» тип зліва від прабатьківського.

Змінні типу «об’єкт» можуть бути динамічними, тобто оголошуватися як вказівники.

VAR

Dyn_ St: ^ TStudent;

Dyn_ St 1: ^ TStudent 1;

Після створення динамічних об’єктів процедурою чи функцією New вказівники (як розіменовані, так і самі по собі) можуть присвоюватися один одному. Правила сумісності залишаються тими ж: коректними будуть лише присвоювання вказівників на спадкоємців вказівникам на прабатьків.

Dyn_ St: = Dyn_ St1;

Dyn_ St ^: = Dyn_ St 1^;

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

Procedure Show_ Fields(Obj: TStudent);

то допустимими типами фактичних параметрів можуть бути TStudent i TStudent1.

А в такому випадку

Procedure Show_ Fields(Obj: TStudent1);

допустимий тип фактичних параметрів лише TStudent1.

Інкапсуляція

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

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

Type

TStudent=OBJECT

  Name:String[30];

  Date:String[10];

  Rate:Real;

  Procedure Init(Nm,Dt:String; R t:Real);

  Function GetName:String;

  Function Get Date:String;

Function Get Rate: Real;

  Procedure ShowName;

  Procedure ShowDate;

  Procedure ShowRate;

END;

 

TStudent1=OBJECT(TStudent)

  Bal:Real;

  Procedure Init(Nm,Dt:String; R t,Bl:Real);

  Function Get Bal: Real;

  Function Get Sum: Real;

  Procedure ShowBal;

  Procedure ShowAll;

END;

Методи ShowName, ShowDate, ShowRate і ShowBal виводять прізвище, дату народження, розмір стипендії і середній бал відповідно. Метод Get Sum використовує Bal для розрахунку суми стипедії від середнього балу. Метод ShowAll виводить значення всіх полів одночасно.

Для екземпляру St1 типу TStudent 1 можна використовувати набір методів для непрямої роботи з полями даних, наприклад:

WITH St1 DO BEGIN

Init(‘Ляшук С.Т. ’,’10.02.1995’,700,4.5);

ShowAll;

END;

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

 Перевизначення методів

При використанні стандартних методів Pascal-ю дуже важко або й зовсім неможливо створювати гнучкі процедури, які б працювали з формальними параметрами змінних типів, як це робить, наприклад, процедура writeln, що може виводити на екран дані типу string, real, integer, boolean і споріднені з ними.

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

Пояснимо цей процес на прикладі. Попередньо ми створили два об’єктні типи:

  Type

TStudent=OBJECT

  Name:String[30];

  Date:String[10];

  Rate:Real;

  Procedure Init(Nm,Dt:String; R t:Real);

  Function GetName:String;

  Function Get Date:String;

Function Get Rate: Real;

  Procedure ShowName;

  Procedure ShowDate;

  Procedure ShowRate;

END;

 

TStudent1=OBJECT(TStudent)

  Bal:Real;

  Procedure Init(Nm,Dt:String; R t,Bl:Real);

  Function Get Bal: Real;

  Function Get Sum: Real;

  Procedure ShowBal;

  Procedure ShowAll;

END;

 

Дочірній тип успадковує від батьківського процедуру Init. Але, оскільки цей дочірній тип має додаткове поле даних Bal, яке батьківською процедурою Init не визначається, то цю процедуру необхідно перевизначити. Зробимо це так:

PROCEDURE TStudent1.Init(Nm,Dt:string;rt,bl:real);

Begin

TStudent.Init (Nm,Dt,Rt);

Bal:=bl;

End;

Зверніть увагу, що ми використовуємо метод ініціалізації об’єкту TStudent.  Синтаксис виклику успадкованого методу такий:

Предок.Метод;

де Предок – ідентифікатор батьківського типу, а Метод – ідентифікатор методу цього типу.

Відзначимо також, що перевизначати можна тільки методи, але в жодному випадку не поля даних.

 

Підсумок

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

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

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

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


 

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

1. Вибрати правильний запис, який би реалізував механізм успадковування

а) TStudent1=OBJECT:TStudent

  Bal:Real;

END;

б) TStudent1=OBJECT(TStudent)

  Bal:Real;

END;

в) TStudent1=OBJECT()

TStudent+Bal:Real;

END;

2. Нехай змінні a і b - об’єктного типу, причому a – дочірнього, b – батьківського. Який із записів правильний:

а) a:=b;

б) b:=a;

в) Обидві операції коректні

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

а)PRIVATE

б)PUBLIC

в)CONSTRUCTOR

4. Як називається об’єднання в об’єкті коду та даних

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

 


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

Попередньо описані методи об’єктів 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 батьківського і дочірнього об’єкту виводяться дещо по-різному:

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



Поделиться:


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

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