МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах
РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ" ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах Гендерна антидискримінаційна експертиза може зробити нас моральними рабами ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів
Контакти
Тлумачний словник Авто Автоматизація Архітектура Астрономія Аудит Біологія Будівництво Бухгалтерія Винахідництво Виробництво Військова справа Генетика Географія Геологія Господарство Держава Дім Екологія Економетрика Економіка Електроніка Журналістика та ЗМІ Зв'язок Іноземні мови Інформатика Історія Комп'ютери Креслення Кулінарія Культура Лексикологія Література Логіка Маркетинг Математика Машинобудування Медицина Менеджмент Метали і Зварювання Механіка Мистецтво Музика Населення Освіта Охорона безпеки життя Охорона Праці Педагогіка Політика Право Програмування Промисловість Психологія Радіо Регилия Соціологія Спорт Стандартизація Технології Торгівля Туризм Фізика Фізіологія Філософія Фінанси Хімія Юриспунденкция |
|
|||||||
Застосування поліморфізмуПриклад 2 У наступній програмі показано, як при спадкуванні зберігається віртуальна природа функції. //Віртуальна функція при спадкуванні зберігає свою віртуальну природу class base { public: virtual void func () { cout <<" Вионання функції func () базового класу \ n "; } }; class derivedl: public base { public: void func () { cout << " Виконання функції func () класу derivedl \ n "; } ); //Клас derivedl успадковується класом derived2 class derived2: public derivedl { public: void func () { cout <<”Виконання функції func () класу derived2 \ n”; } }; void main () { base * p; base ob; derivedl d_obl; derived2 d ob2; р = &ob; p‑> func (); //функція func () базового класу р = & d_obl; p-> func (); //функція func () похідного класу derivedl р = & d_ob2; p-> func (); //функція func () похідного класу derived2 }
У цій програмі віртуальна функція func () спочатку успадковується класом derivedl, в якому вона підмінюється. Далі клас derivedl успадковується класом derived2. У класі derived2 функція func () знову підмінюється. Оскільки віртуальні функції є ієрархічними, то якби в класі derived2 функція func () не підмінялася, при доступі до об’єкта d_ob2 використовувалася б перевизначена в класі derivedl версія функції func (). Якби функція func () не підмінялася ні в класі derivedl, ні в класі derived2, то всі посилання на функцію func () ставилися б до її визначення в класі base.
Є два терміни, які часто асоціюються з об’єктно-орієнтованому програмуванні. Цими термінами є раннє зв’язування (early binding) і пізніше зв’язування (late binding). Важливо розуміти, що означають зазначені терміни. Раннє зв’язування відноситься до подій, про які можна дізнатися в процесі компіляції. Особливо це стосується викликів функцій, які настроюються при компіляції. Функції раннього зв’язування ‑ це "нормальні" функції, перевантажені функції, невіртуальні функції-члени і дружні функції. При компіляції функцій цих типів відома вся необхідна для їх виклику адресна інформація. Головною перевагою раннього зв’язування є те, що воно забезпечує високу швидкодію програм. Визначення потрібної версії функції під час компіляції програми ‑ це найшвидший метод виклику функцій. Головний недолік ‑ втрата гнучкості. Пізнє зв’язування відноситься до подій, які відбуваються в процесі виконання програми. Виклик функції пізнього зв’язування ‑ це виклик, при якому адреса функції, що викликається, до запуску програми невідома. У С + + віртуальна функція є об’єктом пізнього зв’язування. Якщо доступ до віртуальної функції здійснюється через вказівник базового класу, то в процесі роботи програма повинна визначити, на який тип об’єкта він посилається, а потім вибрати, яку версію підміненої функції виконати. Головною перевагою пізнього зв’язування є гнучкість під час роботи програми. Програма може легко реагувати на випадкові події. Його основним недоліком є те, що потрібно більше дій для виклику функції. Це, зазвичай, робить такі виклики повільнішими, ніж виклики функцій раннього зв’язування. Залежно від потрібної ефективності, слід приймати рішення, коли краще використовувати раннє зв’язування, а коли ‑ пізнє. Нижче наведена програма, у якій визначено вихідний базовий клас для зв’язаного списку цілих. Інтерфейс списку визначається за допомогою чисто віртуальних функцій store () і retrieve (). Для зберігання значення у списку викликається функція store (). Щоб відібрати значення зі списку викликається функція retrieve (), У базовому класі list для виконання цих дій ніякого вбудованого методу не задається. Замість цього в кожному похідному класі явно визначається, який тип списку буде підтримуватися. У програмі реалізовані списки двох типів; черга і стек. Хоча способи роботи з цими двома списками зовсім різні, для доступу до кожного з них застосовується один і той же інтерфейс.
//Демонстрація віртуальних функцій # include <iostream> # include <cstdlib> # include <cctype> class list { public: list * head; //вказівник на початок списку list * tail; //вказівник на кінець списку list * next; //вказівник на наступний елемент списку int num; / / число для зберігання list ( ) {head = tail = next = NULL;} virtual void store (int i} = 0; virtual int retrieve () = 0; }; //Створення списку типу чергу class queue: public list { public: void store (int i); int retrieve (); }; void queue:: store (int i) { list * item; item = new queue; if (!item) { cout <<" Помилка виділення пам’яті \ n "; exit (1); } item‑> num = i; //Додавання елемента в кінець списку if (tail) tail‑> next = item; tail = item; item‑> next = NULL; if (! head) head = tail; } int queue:: retrieve () { int i; list * p; if (!head) { cout <<" Список пустий \ n "; return 0; } //Видалення елемента з початку списку i = head‑> num; р = head; head = head‑> next; delete p; return i; } //Створення списку типу стек class stack: public list { public: void store (int i); int retrieve (); }; void stack:: store (int i) { list * item; item = new stack; if (! item) { cout <<" Помилка виділення пам’яті \ n "; exi t (1); } item-> num = i; //Додавання елемента в початок списку if (head) item-> next = head; head = item; if (! tail) tail = head; } int stack:: retrieve () { int i; list *p; if (!head) { cout <<" Список пустий \ n "; return 0; } //Видалення елемента з початку списку i = head-> num; р = head; head = head-> next; delete p; return i; } void main () { list * p; //Демонстрація черги queue q_ob; p = & q_ob; //вказує на чергу p-> store (1); p-> store (2); p-> store (3); cout <<" Черга: “; cout << p-> retrieve (); cout << p-> retrieve (); cout <<p-> retrieve (); cout << “ \ n “; //Демонстрація стека stack s_ob; p = &s_ob; //вказує на стек p ‑> store (1); p-> store (2); p-> store (3); cout <<" Стек: “; cout << p-> retrieve (); cout << p-> retrieve (); cout << p-> retrieve (); cout << ” \ n”; }
Функція main () в програмі зі списками тільки ілюструє роботу класів. Однак для вивчення динамічного поліморфізму спробуємо використати у попередній програмі наступну функцію main ():
void main () { list * p; stack s_ob; queue q_ob; char ch; int i; for (i = 0; i <10; i++) { cout <<" Стек або Черга? (С / 0): "; cin >>ch; ch = tolower (ch); if (ch = = ‘o ‘) p = & q_ob; else p = & s_ob; p-> store (i); } cout <<"Введіть К для завершення роботи \ n"; for (;;) { cout <<"Вивести елемент iз Стека або Черги? (С/О):"; cin >> ch; ch = tolower (ch); if (ch = = ‘k’) break; if (ch = = ‘o’) p = & q_ob; else p = & s_ob; cout << p-> reteieve {)« “\n”; } cout <<”\ n”; }
Функція main () показує, як випадкові події, що виникають при виконанні програми, можуть бути легко опрацьовані, якщо використовувати віртуальні функції і динамічний поліморфізм. У програмі виконується цикл for від 0 до 9. Протягом кожної ітерації пропонується вибір типу списку ‑ стек чи чергу. Базовий вказівник р встановлюється на вибраний об’єкт (чергу або стек), і це значення запам’ятовується. Після завершення циклу починається інший цикл, в якому пропонується вибрати список для вилучення значення. Відповідно вибирається число із зазначеного списку. Незважаючи на те, що цей приклад досить простий, він дозволяє зрозуміти, як поліморфізм може спростити програму, якій необхідно реагувати на випадкові події. Наприклад, операційна система Windows взаємодіє з програмою за допомогою повідомлень. Ці повідомлення генеруються як випадкові, і програма повинна якось реагувати на кожне одержане повідомлення. Одним із можливих способів опрацювання цих повідомлень є використання чисто віртуальних функцій.
Читайте також:
|
||||||||
|