Завдання до лабораторної роботи № 6

Лабораторна робота № 6.

Використання віртуальних функцій

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

Обладнання: ПК, програмне забезпечення BorlandC++, методичні вказівки та завдання до лабораторної роботи.

Короткі теоретичні зведення

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

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

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

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

Формат оголошення віртуальної функції:

virtual <тип результату функції> <ім’я функції> (<список параметрів>);

Формат визначення віртуальної функції:

virtual <тип результату функції> <ім’я класу> :: <ім’я функції> (<список параметрів>)

{ тіло функції }

Правила використання віртуальних функцій такі:

- віртуальні функції не можуть бути перевизначені в похідних класах з іншими типами значень, що повертаються;

- перевизначення віртуальних функцій з іншим переліком параметрів неможливо;

- конструктор не може бути віртуальним;

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

Компілятор виявляє ситуації використання імен, визначених більш, ніж в одному базовому класі і, якщо виникає конфлікт імен, то видає повідомлення “Member is ambiguous…” (“Неоднозначний елемент…”). Для вирішення конфлікту імен необхідно використовувати оператор дозволу області видимості :: с указівкою класу, до якого належить відповідне ім’я.

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

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

Приклад.

class CA: public IX { public:

CA(double d) : m_xFx2(d*d) { }                           // Конструктор

virtual void Fx1() { cout << "CA::Fx1" << endl }

virtual void Fx2() { cout << "CA::Fx2" << endl }

double m_Fx2;                                                       // Дані примірника

};

Таблиця vtbl і дані класу СА, згенеровані компілятором, показані на рис. 11.2. Дані примірника потенційно доступні через покажчик рА класу СА.

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

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

#include <iostream.h>

#include <stdlib.h>

class massiv {    int *num;

int kol;

public:

massiv (int n);

void print ();

virtual int kolich (){return kol;}

void put (int k,int n){num[k]=n;}

~massiv (){delete num;}

};

massiv::massiv (int n)

{   num=new int[n];

kol=n;

for (int i=0;i<kol;i++) num[i] = random (100) - 50;

}

void massiv::print ()

{   for (int i=0; i<kolich(); i++) cout<<num[i]<<" ";

cout<<endl;

}

class stec : public massiv {     int top;

public:

stec (int);

virtual int kolich () { return top; }

void pop (int k);

};

stec :: stec (int n) : massiv (n) { top=0; }

void stec :: pop (int k) { put(top++,k); }

void main ()

{  randomize ();

massiv a (10); stec b (10);

a.print ();

b.pop (random (100) - 50);

b.print ();

}

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

Приклад.

#include <iostream.h>

class Base { public:

Base(){};

Print(){ cout<<”I’m a Base print”<<endl; }

virtual View(){ cout<<”I’m a Base view”<<endl; }

};

class Derived : public Base { public:

Derived(){};

Print(){ cout<<”I’m a Derived print”<<endl;}

View(){ cout<<”I’m a Derived view”<<endl;}

};

main ()

{   Base *A=new Base;

Derived *B=new Derived;

Base *C;

A->Print(); A->View();

B->Print(); B->View();

C=(Base *) B;

C->Print(); C->View();

}

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

Завдання до лабораторної роботи № 6

Побудувати конкретний клас (у відповідності до варіанту), з врахуванням необхідності приховання даних, в якому передбачити: конструктори, деструктор, функції-модифікатори і функції-селектори. Функції-члени мають бути визначені за межами класу. Побудувати похідні класи у відповідності до варіанту. Визначити потрібні віртуальні функції.

Самостійно продумати і реалізувати спосіб демонстрації отриманих результатів.

Варіант1.

1. Клас “прямокутник”: координати верхнього лівого і нижнього правого кутів, порядковий номер.

2. Похідні: “ромб” (довжина другої діагоналі) і коло (центр – перші дві координати, діаметр – діагональ прямокутника). В базовому і похідних класах визначити функцію draw ().

3. Перевантажити унарну операцію - - (зменшення на 1 розміру фігури), бінарну С=А+В – як дублювання в С об’єкта А із збільшенням діагоналі на розмір діагоналі В. Функцію draw () перетворити на віртуальну.

Варіант 2.

1. Клас “фігура”: координати на шахівниці, колір. Метод – “хід” – в одному з двох напрямків.

2. Похідні класи: “шашка” – (порядковий номер) і “дамка”, методи – “хід” і “удар”.

3. В класах перевантажити бінарну функцію А-В як “А б’є В” і оператор перетворення типу (із “шашка” в “дамка”). Функцію “хід” перетворити на віртуальну.

Варіант 3.

1. Клас “нота”: назва, октава, тривалість звучання.

2. Похідні класи: “звук” (частота) і “зображення” (координати на екрані лівого верхнього кута фрагменту нотного стану). В обох класах – порядковий номер ноти, визначити функцію output – для кожного класу з різною реалізацією.

3. В класах перевантажити операції постфіксний ++ – для отримання наступної ноти, префіксний ++ – для збільшення тривалості звучання ноти вдвічі. Функцію output () перетворити на віртуальну.

Варіант 4.

1. Клас “іграшка”: ціна, назва, кількість на складі.

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

3. В класах перевантажити операції “++” – як збільшення кількості на складі; “<” – як порівняння цін. Функцію print перетворити на віртуальну.

Варіант 5.

1. Клас “Товар”: назва, порядковий номер, постачальник, ціна, кількість одиниць.

2. Похідні класи: “Промисловий товар” (умови транспортування, місце знаходження: на складі, в торговому залі, на вітрині) і “Харчовий продукт” (дата виготовлення, термін зберігання). В усіх класах визначити функцію alarm() – для промислового товару з повідомленням із умов транспортування (“не кантовать”, “осторожно!”, ...), або “товар непридатний для споживання” – для харчового, для “Товар” – просто назва товару.

3. В класах перевантажити операції “++” – як збільшення кількості одиниць для харчового і зміна місця знаходження для промислового; “<” – порівняння за терміном зберігання для харчового і за ціною для промислового. Функцію alarm () перетворити на віртуальну.

Варіант 6.

1. Клас “Точка на площині”: координати.

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

3. В класах перевантажити операції “<” і “+” бінарні і “-” унарний – у відповідності до їх семантики. Функцію print перетворити на віртуальну.

Варіант 7.

1. Клас “Точка на площині”: координати.

2. Похідні класи: “коло” (радіус) і “прямокутник” (координати протилежного кута). В усіх класах визначити функцію move – для руху об’єкта на 1 позицію по x і по y.

3. В класах перевантажити операції “++” – як збільшення розміру об’єкта на 1, “<” – за розміром і С=А+В – об’єкт С – “концентричний” відносно А і більший на відповідні розміри об’єкта В. Функцію move перетворити на віртуальну.

Варіант 8.

1. Клас “учасник змагань”: країна, вид спорту, назва учасника.

2. Похідні класи: “футбольна команда” (кількість забитих голів, результат, порядковий номер) і “легкоатлет” (час, час лідера, відставання від лідера, місце у фінальній таблиці). В усіх класах визначити функцію print – друк тільки назви учасника або і назви і кількості голів для футбольної команди або часу для легкоатлета.

3. В класах перевантажити операцію “++” – як збільшення на 1 кількості забитих голів або зменшення на 1 місця в фінальній таблиці; бінарний “-” – як результат конкретної гри: “нічия”, “перемога” або “поразка” в полях “результат”. Для об’єктів легкоатлет А-В щось виконує тільки для ситуації, коли А стає новим лідером, тобто його час менший, ніж час лідера, тоді необхідно змінити відповідні значення для обох об’єктів. Функцію print перетворити на віртуальну.

Варіант 9.

1. Клас “Станція”: координати, назва.

2. Похідні класи: “Радіостанція” (досяжність, вартість ефірного часу, діапазон частот, порядковий номер), “Залізнична станція” (кількість запасних шляхів, тривалість зупинки швидкісних потягів, категорія, порядковий номер), визначити функцію view – для кожного класу з різною реалізацією (назва і категорія).

3. В обох класах перевантажити бінарну операцію “+”: результуючий об’єкт для радіостанцій має сумарну досяжність, мінімальну вартість ефірного часу і об’єднання діапазону частот, для залізничних – сумарну кількість запасних шляхів, максимальну категорію і максимальну тривалість зупинки. Унарна “++” – збільшення відповідно вартості ефірного часу і кількості запасних шляхів. Функцію view перетворити на віртуальну.

Варіант 10.

1. Клас “кліматичні умови”: температура. освітленість. вологість, кислотність грунта.

2. Похідні клас: “кліматичні умови в теплиці”(оптимальні кліматичні умови, допуски), “кліматичні умови на городі” (критичний рівень вологості, критичні рівні кислотності), визначити функцію show – для “кліматичні умови” – поточний стан, для додаткових класів – виводити тільки ті значення, які перевищують критичні, і величину цього перевищення.

3. В обох класах перевантажити бінарну операцію “= =”, якщо всі параметри обох об’єктів лежать в межах допустимих, або якщо для обох об’єктів є хоч один параметр, що знаходиться за цими межами і унарну – префіксний “++” для збільшення рівня вологості на 1. Функцію show перетворити на віртуальну.

Контрольні питання

1. Що представляє собою віртуальна функція?

2. Як віртуальні функції допомагають реалізовувати динамічний поліморфізм?

3. Чи можна віртуальну функцію визначати як static?

4. Наведіть порівняльну характеристику віртуальних та звичайних функцій.


Дата добавления: 2022-12-03; просмотров: 13; Мы поможем в написании вашей работы!

Поделиться с друзьями:




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