
C _Учебник_МОНУ
.pdf
Об’єктно-орієнтоване програмування |
519 |
|
|
paral d(StrToFloat(Edit1->Text),StrToFloat(Edit2->Text), StrToFloat(Edit5->Text));
// Виведення результатів обчислень об‟єктів
Memo1->Lines->Add("Прямокутник = "+FloatToStr(b.arear())); Memo1->Lines->Add("Циліндр = "+FloatToStr(c.areac())); Memo1->Lines->Add("Паралелепіпед = "+FloatToStr(d.areap()));
}
Форма з результатами обчислень має вигляд:
14.8 Поліморфізм
При успадкуванні деякі методи класу мають можливість бути замінені на інші. Так, батьківський клас способів зв‟язку (див. рис. 14.1) матиме узагальнений метод – спосіб передавання інформації. У похідних класах цей метод буде уточнено: радіозв‟язок – це передавання радіосигналів від радіостанції до радіоприймачів, поштовий зв‟язок – це перевезення транспортом поштових відправлень (посилок, бандеролей, листів тощо), супутниковий зв‟язок – це передавання сигналів на супутники та прийом цих сигналів супутниковими антенами. Отже, одне ім‟я методу використовується для розв‟язання декількох схожих, але технічно різних задач. Таке змінювання змісту методу називається поліморфізмом. Взагалі поліморфізм (polymorphism) (від грецької – polymorphos) – це здатність об‟єкта змінювати форму (poly означає багато, а morphism має відношення до змінювання форми). Отже поліморфний об‟єкт, являє собою об‟єкт, який може набувати різноманітних форм.
Мета поліморфізму в об‟єктно-орієнтованому програмуванні – використання одного імені для схожих дій (методів) класу. Виконання кожної конкретної дії буде визначено типом даних. У різних мовах програмування поліморфізм реалізовано різноманітними засобами. Наприклад, у Pascal та C++ його реалізовано за допомогою механізму віртуальних функцій. Разом з тим, у мові С++ поліморфізм підтримується недостатньо, наприклад, обчислення абсолютного значення змінної можна виконати трьома функціями: abs(), labs() та fabs(). Ці функції обчислюють та повертають абсолютне значення змінних цілого, довгого цілого та дійсного типів відповідно. У Pascal така задача виконується однією функцією abs(). У мові С++ вибір конкретної функції для цієї задачі здійснює програміст відповідно до типу даних.
Об’єктно-орієнтоване програмування |
521 |
|
|
Для суто віртуальної функції використовується формат: virtual <тип> <ім‟я_функції> (<список_параметрі в >) = 0;
Ключовою частиною цього оголошення є присвоєння суто віртуальній функції значення нуль. Це повідомляє компіляторові, що в батьківському класі немає тіла функції. Якщо функцію задано як суто віртуальну, то це означає, що вона обов‟язково повинна бути заміненою в кожному похідному класі, інакше при компіляції виникне помилка. Отже, створення суто віртуальних функцій – це гарантія того, що похідні класи забезпечать їхнє перевизначення. Якщо клас містить хоча б одну суто віртуальну функцію, то його називають абстрактним класом. Оскільки в абстрактному класі є хоча б одна функція, в якої відсутнє тіло функції, технічно такий клас не є повністю визначений, і для нього неможливо створити жодного об‟єкта. Тому абстрактні класи можуть бути лише похідними.
Основні концепції поліморфізму в мові програмування С++:
поліморфізм – це властивість об‟єкта змінювати форму під час виконання програми;
для створення методів, які є поліморфними, у програмі необхідно ви-
користовувати віртуальні (virtual) функції;
якщо об‟єкти батьківського (абстрактного) класу не призначені для реалізації, необхідно ввести у клас хоча б одну суто віртуальну функцію;
будь-який клас, похідний від батьківського, має можливість використовувати чи перевантажувати віртуальні функції;
для створення поліморфного об‟єкта в С++ слід використовувати вказівник на об‟єкт батьківського класу;
поліморфізм спрощує програмування та створення поліморфних об‟єктів і зменшує складність програм.
Розглянемо механізм поліморфізму на прикладах.
Приклад 14.6 Створити поліморфний клас – телефон, який відображує (імітує) телефонні операції: набирання номера, дзвінок, роз‟єднання та індикацію зайнятості лінії зв‟язку. Передбачити у програмі можливість імітувати, за бажанням, роботу дискового, кнопкового чи платного телефону (25 копійок, щоб подзвонити). Тобто об‟єкти класу мають бути поліморфними – від одного дзвінка до іншого об‟єкт-телефон має змінювати форму (своє призначення).
Розв‟язок. Створимо батьківський клас phone – дисковий телефон з полем number – номером телефону і методами: dial – набирання номера, ring – дзвінок, answer – очікування відповіді, hangup – роз‟єднання. Далі створимо два похідні класи: touch_tone – кнопковий телефон та pay_phone – платний телефон, причому в цих класах будуть визначені свої власні методи dial.
Код програми з виведенням результатів у консольному режимі має такий вигляд:
#include <iostream.h> #include <string.h> #include <conio.h>
Об’єктно-орієнтоване програмування |
523 |
|
|
poly_phone->dial("818-555-1212");
// Змінення форми об‟єкта на кнопковий телефон poly_phone = (phone *) &home_phone; poly_phone->dial("303-555-1212");
// Змінювання форми об‟єкта на платний телефон poly_phone = (phone *) &city_phone; poly_phone->dial("212-555-1212"); getch();
return ;
}
Результати виконання програми:
Набирання номера 602-555-1212 Пік, пік. Набирання номера 212-555-1212 Будь ласка, сплатіть 25 копійок Набирання номера 212-555-1212
Поліморфні об’єкти: Набирання номера 818-555-1212
Пік, пік. Набирання номера 303-555-1212 Будь ласка, сплатіть 25 копійок Набирання номера 212-555-1212
Наведені класи телефону мають однакову назву, але різну за виконанням функцію dial(). Цю функцію було визначено як віртуальну (з ключовим словом virtual) у батьківському класі phone.
Для створення поліморфного об‟єкта у програмі використано вказівник на об‟єкт батьківського класу (phone *poly_phone). Для змінювання форми об‟єкта цьому вказівникові надано адресу об‟єкта похідного класу:
poly_phone = (phone *) &home_phone;
Вираз у круглих дужках (phone *), записаний за оператором присвоєння, є операцією зведення типів, яка сповіщає компілятору C++, що вказівнику на змінну одного типу (phone) треба надати адресу змінної іншого типу (home_phone). Оскільки програма присвоює вказівнику об‟єкта poly_phone адреси різних об‟єктів, то цей об‟єкт може змінювати свою форму, а, отже, він є поліморфним. Згідно з програмою, об‟єкт poly_phone змінює форму з дискового телефону на кнопковий, а після цього – на платний.
Приклад 14.7 Побудувати батьківський клас Tvirob з полями: назва виробу, кількість випробувань виробу на якість, кількість виробів, які успішно пройшли випробування, кількість таких з них, які виявилися нестандартними. Метод класу визначає якість за формулою:
Q = кількість випробувань виробу / кількість успішних випробувань.
Побудувати похідний клас TPvirob, який крім батьківських полів має додаткове поле (P) – кількість виробів, які не відповідають стандарту (за розміром, кольором тощо) та визначає якість виробу за новою формулою:
Qр = Q – 2* P / кількість випробувань виробу на якість.
Об’єктно-орієнтоване програмування |
525 |
|
|
Файл Unit3.h – оголошення похідного класу
#ifndef Unit3H #define Unit3H #include "Unit2.h"
//------------------------------------------------------------
class TPvirob : public Tvirob { private:
int kolV; // Додаткове поле нащадка protected:
float rachest(void); public:
TPvirob(AnsiString iNAME,int ikolp, int ikolpr, int ikolV);
};
#endif
Файл Unit3.cpp – визначення методів похідного класу
#pragma hdrstop #include "Unit3.h"
//------------------------------------------------------------
#pragma package(smart_init) // Конструктор нащадка
TPvirob::TPvirob(AnsiString iNAME,int ikolp,int ikolpr,int ikolV)
:Tvirob (iNAME,ikolp,ikolpr)
{kolV=ikolV; }
float TPvirob::rachest()
{ float Q=Tvirob::rachest(); return Q-2.0*kolV/kolp; }
Файл Unit1.cpp – головний модуль проекту
#include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" #include "Unit3.h"
//------------------------------------------------------------
#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;
//------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
}
//------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{AnsiString NAME = Edit1->Text; int kp = StrToInt(Edit2->Text);


Об’єктно-орієнтоване програмування |
527 |
|
|
приклад: Show(), Hide(), SetFocus(), GetParentComponent() тощо) реалізують певну стандартну поведінку компонентів. Події – це спеціальні методи класу, за допомогою яких компонент повідомляє користувача про те, що над ним виконали якусь дію (наприклад: Click, MouseDown, KeyPress тощо) і буде виконано програмний код, передбачений програмістом. Перелік усіх елементів компонентів можна переглянути за допомогою довідкової системи Help.
Класи компонентів мають ієрархічну структуру. Наведемо фрагмент дерева класів бібліотеки візуальних компонентів C++ Builder (рис. 14.3).
TObject
TPersistent
TComponent
TControl TMainMenu
TTime …
TGraphicControl |
|
TWinControl |
|
TLabel |
… |
|
|
|
|
|
|
TImage |
… |
TEdit |
|
TMemo |
|
TStringGrid |
|
TButton |
… |
|
|
|
|
|
|
|
|
|
|
Рис. 14.3. Ієрархія класів бібліотеки VCL
(курсивом позначено класи компонентів)
Клас TObject – це базовий клас, який є спільним предком усіх класів. Він забезпечує такі методи: здібність конструктора створювати, а деструктора знищувати об‟єкт класу в динамічній пам‟яті, опрацювання повідомлень Windows тощо. До методів цього класу не слід звертатися зі своїх програм, оскільки вони можуть бути перевизначеними у похідних класах.
Клас TPersistent – похідний клас від TObject. Це абстрактний клас, який визначає низку методів копіювання об‟єктів подібних класів, повернення власника даного об‟єкта, завантаження та збереження спеціальної інформації.
Клас TComponent – похідний клас від TPersistent та батьківський клас для усіх компонентів. Цей клас забезпечує відображення компонентів та маніпуляцію з ними в редакторі форм. Не слід створювати об‟єкти цього класу у своїх програмах, але можна використовувати цей клас для створювання похідних класів. Похідними від цього класу є класи невізуальних компонентів (наприклад: TMainMenu, TTimer, OpenDialog тощо), які є видимі як піктограми на формі під час проектування, але їх не видно під час виконання.
528 |
Розділ 14 |
|
|
Клас TControl – базовий клас усіх візуальних компонентів. Цей клас встановлює властивості компонента: розташування, розміри, видимість, доступність, колір, шрифт тощо. У табл. 14.1 наведено заголовки та призначення деяких методів, притаманних об‟єктам класу TControl, а отже, усім нащадкам цього класу.
|
Таблиця 14.1 |
|
Деякі методи класу TControl |
||
|
|
|
Прототип методу |
Призначення |
|
|
|
|
DYNAMIC void __fastcall |
Викликає функцію відгуку на подію OnClick, яка |
|
Click(void); |
відбувається при клацанні лівою кнопкою миші |
|
DYNAMIC void __fastcall |
Викликає функцію відгуку на подію OnDblClick, |
|
DblClick(void); |
яка відбувається у разі подвійного клацання |
|
|
лівою кнопкою миші |
|
DYNAMIC void __fastcall |
Викликає функцію відгуку на подію OnMouseDown, |
|
MouseDown(TMouseButton |
яка відбувається при клацанні кнопки миші. |
|
Button, |
Параметр Button визначає кнопку: ліва, середня |
|
Classes::TShiftState |
||
чи права. Параметр Shift зазначає, чи було |
||
Shift, int X, int Y); |
||
натиснуто якусь з кнопок клавіатури: Shift, |
||
|
||
|
Ctrl, Alt. Параметри X, Y – координати миші |
|
DYNAMIC void __fastcall |
Викликає функцію відгуку на подію |
|
MouseMove |
OnMouseMove, яка відбувається при переміщуван- |
|
(Classes::TShiftState |
ні курсора |
|
Shift, int X, int Y); |
||
миші. Параметри є аналогічні до наведених вище |
||
|
||
DYNAMIC void __fastcall |
Повідомляє про те, що розміри об‟єкта змінилися |
|
Resize(void); |
|
|
|
|
|
DYNAMIC void __fastcall |
Викликає функцію відгуку на подію OnMouseUp, |
|
MouseUp |
яка відбувається при відпусканні кнопки миші. |
|
(TMouseButton Button, |
Параметри є аналогічні до параметрів методу |
|
Classes::TShiftState |
||
MouseDown |
||
Shift, int X, int Y); |
||
|
Усі ці методи у класі TControl вміщено до секції protected. Здебільшого наведені методи не викликаються безпосередньо, тобто за явними звертаннями у програмах. Іноді їхні прямі виклики навіть заборонено (наприклад для методу Resize()). Проте всі вони є доступні для перекриття, на що вказує ключове слово DYNAMIC – аналог слова virtual для компонентів.
Клас TWinControl – базовий клас усіх віконних компонентів. У цьому класі введено віконний дескриптор (window handle), реалізовано здібність приймати фокус введення інформації та обслуговувати події клавіатури. У табл. 14.2 наведено деякі з методів класу TWinControl. Слід звернути увагу на використання слова virtual в оголошенні функції SetFocus замість слова DYNAMIC у переважної більшості компонентів.