Студопедия
Новини освіти і науки:
МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах


РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання


ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ"


ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ


Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків


Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні


Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах


Гендерна антидискримінаційна експертиза може зробити нас моральними рабами


ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ


ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів



Застосування поліморфізму

Приклад 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 взаємодіє з програмою за допомогою повідомлень. Ці повідомлення генеруються як випадкові, і програма повинна якось реагувати на кожне одержане повідомлення. Одним із можливих способів опрацювання цих повідомлень є використання чисто віртуальних функцій.

 


Читайте також:

  1. V. Виконання вправ на застосування узагальнювальних правил.
  2. А.1 Стан , та проблемні питання застосування симетричної та асиметричної криптографії.
  3. Автомобільні ваги із застосуванням цифрових датчиків
  4. Акти застосування норм права в механізмі правового регулювання.
  5. Акти застосування юридичних норм: поняття, ознаки, види.
  6. Акти правозастосування, їх види
  7. Акти правозастосування.
  8. Алгоритм із застосування річної процентної ставки r.
  9. Алгоритм із застосуванням річної облікової ставки d.
  10. Аміноглікозиди (стрептоміцину сульфат, гентаміцину сульфат). Механізм і спектр протимікробної дії, застосування, побічні ефекти.
  11. Аналіз зображувальних засобів. Застосування цілісного аналізу
  12. Антисептики ароматичного ряду (фенол чистий, іхтіол, дьоготь, мазь Вількінсона, лінімент за Вишневським). Особливості протимікробної дії та застосування.




Переглядів: 803

<== попередня сторінка | наступна сторінка ==>
Приклад 1 | Створення шаблону функції та його використання

Не знайшли потрібну інформацію? Скористайтесь пошуком google:

  

© studopedia.com.ua При використанні або копіюванні матеріалів пряме посилання на сайт обов'язкове.


Генерація сторінки за: 0.021 сек.