Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторний практикум з ООП в Visual Studio.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
3.95 Mб
Скачать

Лабораторний практикум 02.07.25 7:16:58

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

Національний лісотехнічний університет України

Світлана КОШИРЕЦЬ,

Микола САЛО,

Ярослав СОКОЛОВСЬКИЙ

ОБ'ЄКТНО-ОРІЄНТОВАНЕ ПРОГРАМУВАННЯ МОВОЮ С++

Лабораторний практикум

Львів

2012

ББК 32.973.26-01+18.2.75

Г85

УДК 681.3.07

Кощирець С.І.

Г 85 О'єктно-орієнтоване програмування мовою С++: Лаб. практ. – Львів: Вид-во НЛТУ України, 2012. – 126 с.: іл. 15, табл. 18.

ISВN 966-0000-00-0

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

Практикум призначено для студентів ВУЗів, що вивчають комп'ютерні науки.

ББК 32.973.26-01+18.2.75

Навчальне видання

Світлана Іванівна КОШИРЕЦЬ – канд. техн. наук, ст. викладач каф. обчисл. техніки

і моделювання технологічних процесів НЛТУ України

Микола Федорович САЛО – асист. каф. обчисл. техніки

і моделювання технологічних процесів НЛТУ України

Ярослав Іванович СОКОЛОВСЬКИЙ – доктор техн. наук, професор каф. обчисл. техніки

і моделювання технологічних процесів НЛТУ України

О'єктно-орієнтоване програмування мовою С++

ISВN 966-0000-00-0 С.І. Коширець, М.Ф. Сало, Я.І. Соколовський, 2012

ЗМІСТ

ВСТУП 27

Лабораторна робота №1. Робота в інтегрованому середовищі Visual Studio C++ 2010 28

1.1. Програма роботи 28

1.2. Вказівки до виконання роботи 28

1.3.Теоретичні відомості 28

1.4. Зразок виконання роботи 32

1.5. Індивідуальні завдання 35

1.6. Контрольні запитання 36

Лабораторна робота №2. Робота з класами, мАСИВИ ОБ’ЄКТІВ 37

2.1. Програма роботи 37

2.2. Вказівки до виконання роботи 37

2.3. Теоретичні відомості 37

2.5. Індивідуальні завдання 43

2.6. Контрольні запитання 45

Лабораторна робота №3. Робота з конструкторами та перевантаження методів класу 46

3.1. Програма роботи 46

3.1. Програма роботи 46

3.2. Вказівки до виконання роботи 46

3.2. Вказівки до виконання роботи 46

3.3. Теоретичні відомості 46

Демонстрація використання перевантажених конструкторів 47

3.4. Розширений опис завдання 51

Створити клас та описати 3–4 перевантажені методи згідно індивідуального завдання. 51

1. Частина 1. «Створення класу» 51

1.1. Описати клас згідно індивідуального завдання, обов’язково створивши у 51

1.1.1. принаймні по одному відкритому (public), закритому (private) та 52

1.1.2. конструктор по замовчуванню, конструктор з параметрами; 52

1.1.3. деструктор; 52

1.1.4. відкриті (public) методи-аксесори для читання та запису закритих та 52

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

1.1.6. власні поля та методи, що дозволяють розширити можливості класу відповідно до тематики індивідуального завдання; 52

1.1.7. метод виводу екземпляру класу на екран; 52

1.1.8. консольний метод ініціалізації екземпляру класу (вводу з клавіатури); 52

1.2. У головній програмі: 52

1.2.1. створити принаймні один екземпляр класу та принаймні один вказівник на екземпляр цього ж класу, проілюструвавши роботу різних типів конструкторів; 52

1.2.2. продемонструвати звертання до полів екземпляру класу та використання методів-аксесорів; 52

1.2.3. створити посилання на екземпляр класу через вказівник та продемонструвати використання полів та методів класу через цей вказівник на екземпляр класу; 52

1.2.4. динамічно створити (new) екземпляр класу, зберігши його адресу у раніше описаному вказівнику, продемонструвати роботу з ним та видалити (delete); 52

1.2.5. продемонструвати роботу з усіма додатково створеними полями та методами; 52

1.2.6. продемонструвати роботу з усіма описаними методами вводу/виводу класу. 52

2. Частина 2. «Перевантаження методів класу» 52

2.1. Описати клас із частини 1 з перевантаженим методом відповідно до індивідуального завдання. 52

2.2. У головній програмі проілюструвати роботу перевантажених методів. 52

3.5. Індивідуальні завдання 52

3.6. Контрольні запитання 58

Лабораторна РОБОТА №4. Перевантаже ння операторів для класу 59

4.1. Програма роботи 59

4.1. Програма роботи 59

4.2. Вказівки до виконання роботи 59

4.2. Вказівки до виконання роботи 59

4.3. Теоретичні відомості 59

4.4. Розширений опис завдання 62

1. Частина 1. «Створення класу» 62

1.1. Описати клас згідно індивідуального завдання, обов’язково створивши у 63

1.1.1. принаймні по одному відкритому (public), закритому (private) та 63

1.1.2. конструктор по замовчуванню, конструктор з параметрами; 63

1.1.3. деструктор; 63

1.1.4. відкриті (public) методи-аксесори для читання та запису закритих та 63

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

1.1.6. власні поля та методи, що дозволяють розширити можливості класу відповідно до тематики індивідуального завдання; 63

1.1.7. метод виводу екземпляру класу на екран; 63

1.1.8. консольний метод ініціалізації екземпляру класу (вводу з клавіатури); 63

1.2. У головній програмі: 63

1.2.1. створити принаймні один екземпляр класу та принаймні один вказівник на екземпляр цього ж класу, проілюструвавши роботу різних типів конструкторів; 63

1.2.2. продемонструвати звертання до полів екземпляру класу та використання методів-аксесорів; 63

1.2.3. створити посилання на екземпляр класу через вказівник та продемонструвати використання полів та методів класу через цей вказівник на екземпляр класу; 63

1.2.4. динамічно створити (new) екземпляр класу, зберігши його адресу у раніше описаному вказівнику, продемонструвати роботу з ним та видалити (delete); 63

1.2.5. продемонструвати роботу з усіма додатково створеними полями та методами; 63

1.2.6. продемонструвати роботу з усіма описаними методами вводу/виводу класу. 63

2. Частина 2. «Перевантаження методів класу» 63

2.1. Описати клас із частини 1 з перевантаженим методом відповідно до індивідуального завдання. 63

2.2. У головній програмі проілюструвати роботу перевантажених методів. 63

4.5. Індивідуальні завдання 63

4.6. Контрольні запитання 69

Лабораторна робота №5. одинарне Успадкування 70

5.1. Програма роботи 70

5.1. Програма роботи 70

5.2. Вказівки до виконання роботи 70

5.2. Вказівки до виконання роботи 70

5.3. Теоретичні відомості 70

5.4. Зразок виконання роботи 72

5.5. Індивідуальні завдання 74

Варіант1. Клас “учасник”: прізвище, телефон, адреса. 74

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

В похідних класах перевантажити бінарні операції порівняння (“<“ та “!=“) – за датою поставлення на облік і тривалістю доповіді; унарний “-“ - для зміни пункту про наявність пільги і про потребу в поселенні - на протилежне значення. 74

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

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

В похідних класах перевантажити бінарний мінус А-В як “А б’є В" і операцію [ ] - за порядковим номером – для виведення координат відповідної фігури. Функцію “хід” перетворити на віртуальну. 74

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

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

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

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

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

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

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

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

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

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

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

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

Варіант 7. Клас “годинник”: стиль відображення (24 чи 12),години, хвилини, секунди. Метод “плюс секунда” – збільшити поточне значення часу на 1 секунду. 75

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

В похідних класах перевантажити операції “++” – для зсуву зображення на 1 позицію; бінарний “+” – для збільшення зображення об’єкта - результату. Функцію draw перетворити на віртуальну. 75

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

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

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

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

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

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

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

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

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

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

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

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

Варіант 12. Клас “довге число”: кількість знаків, основа системи числення. 76

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

В обох класах перевантажити бінарні операції “+”, “-“ і “<” і унарний “-” – у відповідності до звичної семантики цих операцій і незалежно від різниць в системах числення агентів. Функцію view перетворити на віртуальну. 76

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

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

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

Варіант 14. Клас “ істота ”: координати, вік, назва. Метод move – збільшення координат на 1. 76

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

Бінарна операція А-В допустима тільки для об’єктів, які знаходяться поруч (у 8 напрямках) і тільки якщо А – хижак, а В – здобич, або А – здобич, а В - рослина, тоді об’єкт В знищується, а об’єкт А пересувається на одну позицію і його вік збільшується на 1. Функцію move перетворити на віртуальну. 77

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

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

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

Варіант 16. Клас “давач”: поточне значення, максимально і мінімально допустимі, тип (t, p, i, pH), сигнал тривоги. 77

Похідні: “круглий дисплей”(x, y, R), “прямокутний дисплей”(координати протилежних кутів), визначити для базового класу масив максимальних значень за добу для кожного типу. Функція view – поточне і максимальне за добу в залежності від типу - для кожного класу з різною реалізацією і функцію set_current_value, яка має змінювати і поточне значення і, в разі необхідності, максимальне за добу. 77

В обох класах перевантажити бінарну операцію “>” за поточними значеннями, якщо давачи одного типу, і унарну “++” – як R++ і x2++, y2++ відповідно. Функцію view перетворити на віртуальну. 77

Варіант 17. Клас “товар на складі”: назва, кількість, місце розташування) . 77

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

В обох класах перевантажити бінарну операцію “<” за датою поставки і за амплітудою критичних температур, і унарну “++” – збільшення кількості товарів відповідного класу. Функцію attention перетворити на віртуальну. 77

Варіант 18. Клас “фраза”: (кількість слів, кількість символів, кількість різних символів. 77

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

В обох класах перевантажити бінарні операції “= =” – порівняння відповідно до семантики, “&“ – порозрядне для війкового запису чисел або як по символьний перетин для речень з врахуванням місця розташування символів. Функцію view перетворити на віртуальну. 78

Варіант 19. Клас “Число”: кількість цифр, основа системи числення . 78

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

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

5.6. Контрольні запитання 78

Лабораторна робота №6. Множинне успадкування 79

6.1. Програма роботи 79

6.1. Програма роботи 79

6.2. Вказівки до виконання роботи 79

6.2. Вказівки до виконання роботи 79

6.3. Теоретичні відомості 79

6.4. Зразок виконання роботи 81

83

Діаграма класів програмного коду: 84

84

6.5. Індивідуальні завдання 84

До структури розроблених класів, розроблених у ЛР№5 додати ще 1 клас для забезпечення множинного успадкування. 84

Варіант1. 84

А). Клас “учасник”: прізвище, телефон, адреса. 84

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 84

84

Варіант 2. 85

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 85

85

Варіант 3. 85

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 85

85

Варіант 4. 85

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 85

85

Варіант 5. 85

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 86

86

Варіант 6. 86

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 86

86

Варіант 7. 86

А). Клас “годинник”: стиль відображення (24 чи 12),години, хвилини, секунди. Метод “плюс секунда” – збільшити поточне значення часу на 1 секунду. 86

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 86

86

Варіант 8. 86

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 87

87

Варіант 9. 87

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 87

87

Варіант 10. 87

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 87

87

Варіант 11. 87

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 88

88

Варіант 12. 88

А). Клас “довге число”: кількість знаків, основа системи числення. 88

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 88

88

Варіант 13. 88

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 88

89

Варіант 14. 89

А). Клас “ істота ”: координати, вік, назва. Метод move – збільшення координат на 1. 89

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 89

89

Варіант 15. 89

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 89

89

Варіант 16. 90

А). Клас “давач”: поточне значення, максимально і мінімально допустимі, тип (t, p, i, pH), сигнал тривоги. 90

Похідні: “круглий дисплей”(x, y, R), “прямокутний дисплей”(координати протилежних кутів), визначити для базового класу масив максимальних значень за добу для кожного типу. Функція view – поточне і максимальне за добу в залежності від типу - для кожного класу з різною реалізацією і функцію set_current_value, яка має змінювати і поточне значення і, в разі необхідності, максимальне за добу. 90

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 90

90

Варіант 17. 90

А). Клас “товар на складі”: назва, кількість, місце розташування) . 90

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 90

90

Варіант 18. 90

А). Клас “фраза”: (кількість слів, кількість символів, кількість різних символів. 90

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами 90

91

Варіант 19. 91

Клас “Число”: кількість цифр, основа системи числення . 91

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами. 91

91

6.6. Контрольні запитання 91

1. Що таке невизначеність при успадкуванні? 91

2. Наведіть приклад множинного успадкування? 91

3. Наведіть синстаксис множинного успадкування для мови С++. 91

4. Який за замовчуванням модифікатор доступ використовується при успадкуванні? 91

5. Як можна уникнути невизначеності? 91

6. Чи є обмеження у кількості рівнів у ієрархії успадкування? Чому? 91

7. Охарактеризуйте модифікатори доступу при успадкування. 91

Лабораторна робота №7. Поліморфізм та віртуальні функції 92

7.1. Програма роботи 92

7.2. Вказівки до виконання роботи 92

7.3. Теоретичні відомості 92

7.4. Зразок виконання роботи 95

7.5. Індивідуальні завдання 98

7.6. Контрольні запитання 100

Лабораторна робота №8. Шаблони функцій і класів 102

8.1. Програма роботи 102

8.2. Вказівки до виконання роботи 102

8.3. Теоретичні відомості 102

8.4. Зразок виконання роботи 103

8.5. Індивідуальні завдання 106

8.6. Контрольні запитання 109

Лабораторна робота №9. засоби ОПРА ЦЮВАННЯ ВИняткових СИТУАЦІЙ В C++ 110

9.1. Програма роботи 110

9.2. Вказівки до виконання роботи 110

9.3. Теоретичні відомості 110

9.4. Зразок виконання роботи 115

9.5. Індивідуальні завдання 116

9.6. Контрольні запитання 117

Лабораторна робота №10. Стандартні потокові класи 118

10.1. Програма роботи 118

10.2. Вказівки до виконання роботи 118

10.3. Теоретичні відомості 118

10.4. Зразок виконання роботи 120

10.5. Індивідуальні завдання 126

10.6. Контрольні запитання 131

Лабораторна робота №11. Файлові і рядкові потоки 133

11.1. Програма роботи 133

11.2. Вказівки до виконання роботи 133

11.3. Теоретичні відомості 133

11.4. Зразок виконання роботи 134

11.5. Індивідуальні завдання 136

11.6. Контрольні запитання 136

Лабораторна робота №12. Стандартна бібліотека шаблонів STL, контейнери та ітератори 138

12.1. Програма роботи 138

12.2. Вказівки до виконання роботи 138

12.3. Теоретичні відомості 138

12.4. Зразок виконання роботи 142

12.5. Індивідуальні завдання 144

12.6. Контрольні запитання 145

Лабораторна робота №13. Стандартна бібліотека шаблонів STL, Алгоритми 146

13.1. Програма роботи 146

13.2. Вказівки до виконання роботи 146

13.3. Теоретичні відомості 146

13.4. Зразок виконання роботи 148

13.5. Індивідуальні завдання 149

13.6. Контрольні запитання 150

Література 152

ВСТУП

У даному лабораторному практикумі підібрано низку лабораторних робіт, призначених для набуття студентами основних навиків об’єктно-орієнтованого програмування мовою С++ в середовищі Visual Studio.

Практикум побудовано таким чином, що в першій роботі описано методику роботи в інтегрованому середовищі Visual Studio C++, а саме в консольному і візуальному режимах, описано як правильно відлагоджувати та реалізовувати проекти використовуючи дане середовище. Решта робіт присвячені вивченню технології обєктно-орієнтованого і узагальненого підходу до програмування мовою С++. Перша частина робіт дає змогу отримати навики з створення класів та нанаданням їм функціональних можливостей, а також опису їх взаємодії. Дані роботи реалізовують основні принципи ООП: інкапсуляцію, поліморфізм та успадкування через конструктори і деструктори, перевантаження методів та операцій, просте і множинне успадкування, віртуальні функціх та абстрактні класи. Темі потокових класів писвячено дві роботи, які дають змогу навчитись контролювати різного роду потоки і форматувати їх дані при виводі, перевантажувати оператори вводу-виводу для роботи з власними типами даних. Окремою роботою виділено тему оброблення виключень з метою оволодіння концепцією програмування захисту від помилок, шляхом включення в код програми засобів контролю її нормального виконання. Друга частина практикуму дає змогу навчитись застосовувати шаблони проектування для вирішення поставлених задач, а саме вміти створювати контейнери, отримувати доступ до їх елементів за допомогою літераторів і виконувати різноманітні операції над об’єктами, використовуючи різні види алгоритмів.

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

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

В результаті виконання лабораторних робіт студенти:

  • знатимуть синтаксис, симантику, технології та функціональні можливості об’єктно-орієнтованого програмування мовою С++;

  • вмітимуть будувати діаграми класів і варіантів використання та описувати класи і відношення між ними для розв’язування сформульованих задач засобами мови С++, редагувати, відлагоджувати та реалізовувати програми в середовищі Visual Studio, використовувати в програмах шаблони STL для зменшення їх об’єму та часу виконання.

Матеріал цього практикуму значною мірою відповідає робочій навчальній програмі дисципліни "Об'єктно-орієнтоване програмування".

Лабораторна робота №1. Робота в інтегрованому середовищі Visual Studio C++ 2010

МЕТА РОБОТИ: ознайомитись з основними компонентами інтегрованого середовища Visual Studio C++ 2010, навчитись створювати, відлагоджувати та реалізовувати проекти програм використовуючи об’єктно-орієнтоване програмування.

1.1. Програма роботи

1.1.1. Отримати завдання.

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

1.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

1.1.4. Оформити електронний звіт про роботу та захистити її.

1.2. Вказівки до виконання роботи

1.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 1.5 і записує його до звіту.

1.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 1.4.

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

1.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми, які виведені в вікно форми;

  • діаграму класів з поясненням;

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

1.3.Теоретичні відомості

Програма в Visual Studio C++ 2010 являє собою проект, який містить вихідні файли на С++ та файли необхідних ресурсів (рис. 1). Перелік файлів, які входять в проект, а також властивості проекту зберігаються в файлі проекту з розширенням .vcxproj. Збірка проекту – процес перетворення вихідних файлів в деяке представлення: виконуючий файл (.ехе), динамічну (.DLL) чи статичну (.LIB) бібліотеку. В процесі збірки здійснюється компіляція вихідних файлів для отримання об’єктних файлів (файлів з кодом отриманих в результаті трансляції компілятором чи асемблером вихідного тексту програми) і їх компонування (зв’язування об’єктних модулів програми між собою і з бібліотеками часу виконання) в додатки чи бібліотечні модулі.

2

1

3

4

Рис. 1. Вікно середовища Visual Studio C++ 2010

1 – панель інструментів

2 – вікно редактора вихідного коду

3 – панель виводу інформації

4 – провідник задач (Explorer Solution)

Середовище Visual Studio C++ 2010 дає змогу використовувати декілька проектів разом в складі однієї задачі (анг. Solution), що значно полегшує розробку великих програмних комплексів, які складаються з декількох зв’язаних між собою проектів. Саме від налаштування цих зв’язків і залежить хід виконання задачі. Для налаштування зв’язків між проектами слід в контекстному меню проекту обрати пункт Project Dependencies.

Для створення нового проекту слід викликати майстер проектів (File–> New) і обрати тип проекту (рис. 2):

  • Windows Application – додаток з віконним інтерфейсом;

  • Console Application – консольний додаток;

  • Static Library – статична бібліотека, файл .lib, що містить функції, котрі можуть бути скомпоновані в складі інших модулів;

  • Dynamic Library – динамічна бібліотека, .DLL файл, який містить функції, що можуть сумісно використовуватись декількома додатками одночасно;

  • MFC Application – додаток, який використовує бібліотеку базових класів MFC, що дає змогу створити віконні додатки в Windows.

  • ATL Project – СОМ-сервер, організований у вигляді динамічної бібліотеки, виконавчого модуля чи сервісу, які використовують бібліотеку ATL.

Рис. 2. Вікно майстра проектів

Властивості будь-якого проекту можна редагувати, для цього слід обрати в контекстному меню проекту в провіднику задач (Explorer Solution) пункт Properties (рис. 3).

Рис. 3. Налаштування властивостей проекту

Для збірки проекту в складі однієї задачі слід натиснути клавішу F7, а щоб скомпілювати вихідний файл – Ctrl-F7.

Проект може бути поданий в двох основних конфігураціях: робочій і фінальній. Робоча конфігурація (Debug) модуля має більший розмір і меншу швидкодію, але найбільше забезпечує можливості редагування на рівні вихідного коду. При компіляції відключається оптимізація коду, в модуль поміщається додаткова інформація для редагування коду. Фінальна конфігурація (Release) характеризується меншим розміром і більшою швидкодією. Користувач може обрати необхідну конфігурацію із списку, що розкривається на панелі інструментів (рис. 4) і тоді при наступній збірці проект буде скомпільований і скомпонований в обраній конфігурації. Окрім цього користувач може обрати платформу (32-бітну чи 64-бітну) (рис. 4).

Рис. 4. Вибір конфігурації проекту

Для пакетної збірки проекту відразу ж в декількох конфігураціях можна скористатись командою Build–>Batch Build …

Для запуску активного проекту слід натиснути комбінацію Ctrl-F5, але якщо в задачі декілька проектів, то один з них можна помітити як активний обравши в контекстному меню проекту Set as StartUp Project.

Налагодження проекту – це процес пошуку і виправлення помилок в програмі. Для цього в даному середовищі можна використовувати наступні можливості:

  • зупинення виконання програми в вказаних місцях;

  • трасування (покрокове виконання) програми;

  • перегляд і зміна значень змінних і вмістимого комірок пам’яті (в повних версіях середовища).

Для встановлення точок зупинки використовують клавішу F9. Для трасування програм використовують такі клавіші:

  • F10 – виконати текучий оператор без входу в середину функції чи методу класу;

  • F11 – виконати текучий оператор з входом в середину функції чи метод класу;

  • Shift-F11 – продовжити виконання програми до виходу з текучої функції чи методу класу;

  • Ctrl-F10 – продовжити виконання програми до досягнення позиції курсору;

  • Alt-Num* – встановити курсор в позицію виконання наступного оператора;

  • F5 – продовжити виконання програми.

Дане середовище розробки програм дає змогу внести зміни в програму в процесі її виправлення і продовжити виконання виправленої програми без перезапуску. Для цього після внесення змін в програму слід натиснути комбінацію Alt-F10 або одну з команд трасування програми.

Для зупинення роботи програми і виходу з режиму виправлення помилок слід натиснути комбінацію клавіш Shift–F5.

1.4. Зразок виконання роботи

Для створення нового проекту з формами потрібно обрати пункт меню File->New->Project->CLR->Windows Form і вказати ім’я проекту і паку для його зберігання. При цьому повинна з’явитись порожня форма та порожні файли для створення проекту (рис. 5) і ми з допомогою інструментів на панелі Toolbox вставляємо необхідні для її заповнення.

Рис. 5. Вигляд форми і провідника задач для проекту

Для збереження розмірів форми можна заблокувати її розгортання, задавши відповідну властивість форми  MaximizeBox = False.

Тепер для опису класу потрібно обрати пункт меню Project->Add Class

->C++ Class і задати необхідні дані в вікні діалогу (рис. 6).

Рис. 6. Вікно діалогу для опису класу

Після цього середовище само автоматично створить відповідні файли з розширенням .h i .cpp. В заголовний файл потрібно розмістити опис класу (згідно діаграми класів – рис. 7), а в інший – визначення його функцій чи методів.

Файл ZavdClass.cpp

#include "StdAfx.h"

#include "ZavdClass.h"

#include "Math.h"

using namespace std;

// Обчислення функції b[x,y,z]

void ZavdClass::Fn_b(double x, double y, double z)

{

double b1=x*x+tan(pow(y+z,2));

double b2=0.345*y+pow(sin(x*x),2);

double b3=exp(-(x+y)/z);

b=y*(b1/b2+b3);

}

// Обчислення функції a[x,y,z,b]

void ZavdClass::Fn_a(double x, double y, double z)

{

double a1=pow(x+y,2);

double a2=(x+y*y)*pow(b*b+z,0.3);

double a3=x/Faktr(2)+exp(z-2)+y*y/Faktr(3);

a=a1*a2/a3;

}

// Обчислення факторіалу

double ZavdClass::Faktr(int n)

{

double f=1;

if(n > 1)

for(int i=2; i<=n; i++)

f*=i;

return f;

}

Файл ZavdClass.h

#pragma once

ref class ZavdClass

{ double a, b;

public:

ZavdClass() {a=1; b=1;} // Параметризований конструктор

void Fn_b(double x, double y, double z); // Обчислення функції b[x,y,z]

void Fn_a(double x, double y, double z); // Обчислення функції a[x,y,z,b]

double Faktr(int n); // Обчислення факторіалу

double geta() {return a;}

double getb() {return b;}

};

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

double x = System::Convert::ToDouble(xx->Text);

double y = System::Convert::ToDouble(yy->Text);

double z = System::Convert::ToDouble(zz->Text);

ZavdClass Zavd;

Zavd.Fn_b(x, y, z);

Zavd.Fn_a(x, y, z);

aa->Text = System::Convert::ToString(Zavd.geta());

bb->Text = System::Convert::ToString(Zavd.getb());

Не забудьте включити директиву класу до форми. Тепер можна скомпілювати проект використовуючи клавішу F5 або Debug->Start Debugging.

Рис. 7. Діаграма класів

1.5. Індивідуальні завдання

Завдання 1.

Задано x=0.48№, y=0.47№, z=-1.32№ (де № – но­мер ва­рі­ан­ту). Відповідно до номера варіанту потрібно розробити програму з використанням класів для обчислення значень функцій a[x,y,z,b] і b[x,y,z] згідно з такими математичними виразами:

  1. , ;

  2. , ;

  3. , ;

  4. , ;

  5. , ;

  6. , ;

  7. , ;

  8. , ;

  9. , ;

  10. , ;

  11. , ;

  12. , ;

  13. , ;

  14. , ;

15) , .

Результати обчислень вивести у форму.

Завдання 2.

Використовуючи дані з попереднього завдання написати програму для одновимірного табулювання функцій a i b за змінною xп=-1, xк=1, x=0.2 (для виводу результату скористайтесь інструментом MultiLine, у який в циклі виводити значення.

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

1. Що називається класом?

2. Як відбувається оголошення класу?

3. Що таке відкриті та закриті члени класу?

4. Що таке конструктори?

5. Що таке деструктори?

6. Наведіть приклади параметризованих конструкторів.

7. Наведіть варіанти ініціалізації об'єктів.

8. Як здійснюється доступ до членів класу?

9. Для чого використовуються вбудовувані функції?

10. Наведіть приклад використання покажчиків на об'єкти.

11. Наведіть приклад використання посилання на об'єкти.

Лабораторна робота №2. Робота з класами, мАСИВИ ОБ’ЄКТІВ

МЕТА РОБОТИ: освоїти технологію створення програм в консолі з використанням класів, розв’язувати поставлені задачі з масивами об’єктів.

2.1. Програма роботи

2.1.1 Отримати завдання.

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

2.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

2.1.4. Оформити електронний звіт про роботу та захистити її.

2.2. Вказівки до виконання роботи

2.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 2.5 і записує його до звіту.

2.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 2.4.

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

2.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

2.3. Теоретичні відомості

Масиви об'єктів можна створювати так само, як і створюються масиви значень інших типів. Наприклад, у наведеному нижче коді програми створюється клас displayClass, який містить значення розширення для різних режимів відеомонітора. У функції main() створюється масив для зберігання трьох об'єктів типу displayClass, а доступ до них, які є елементами цього масиву, здійснюється за допомогою звичайної процедури індексування елементів масиву.

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

enum resolution {low, medium, high};

// Визначення класу displayClass.

class displayClass { // Оголошення класового типу

int width;

int height;

resolution res;

public:

void setDim(int w, int h) {width = w; height = h;}

void getDim(int &w, int &h) {w = width; h = height;}

void setRes(resolution r) {res = r;}

resolution getRes() {return res;}

};

char names[3][9] = {

"Низький",

"Середній",

"Високий"

};

int main()

{ displayClass ds_mode[3];

int i, w, h;

ds_mode[0].setRes(low);

ds_mode[0].setDim(640, 480);

ds_mode[1].setRes(medium);

ds_mode[1].setDim(800, 600);

ds_mode[2].setRes(high);

ds_mode[2].setDim(1600, 1200);

cout << "Можливі режими відображення даних: \n\n";

for(i=0; i<3; i++) {

cout << names[ds_mode[i].getRes()] << ": ";

ds_mode[i].getDim(w, h);

cout << w << " x " << h << "\n";

}

cout<<"press any key!";

while(!kbhit());

}

Ініціалізація масивів об'єктів

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

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

class demoClass { // Оголошення класового типу

int a, b;

public:

demoClass(int n, int m) { a = n; b = m;}

int getAzm() { return a;}

int getBzm() { return b;}

};

int main()

{

demoClass demoMas[4][2] = {

demoClass(1, 2), demoClass(3, 4),

demoClass(5, 6), demoClass(7, 8),

demoClass(9, 10), demoClass(11, 12),

demoClass(13, 14), demoClass(15, 16)

};

int i,j;

for(i=0; i<4; i++)

for(j=0; j<2; j++){

cout << "demoMas[" << i << "," << j << "] ==> a= ";

cout << demoMas[i][j].getAzm() << "; b= ";

cout << demoMas[i][j].getBzm() << "\n";

}

cout<<"press any key!";

while(!kbhit());

}

Доступ до структури можна отримати безпосередньо або через покажчик на цю структуру. Аналогічно можна звертатися і до об'єкта: безпосередньо (як в усіх попередніх прикладах) або за допомогою покажчика на об'єкт. Щоб отримати доступ до окремого члена об'єкта виключно "силами" самого об'єкта, використовують оператор "крапка". А якщо для цього слугує покажчик на цей об'єкт, необхідно використовувати оператор "стрілка"1.

Щоб оголосити покажчик на об'єкт, використовується аналогічний синтаксис, як і у разі оголошення покажчиків на значення інших типів. У наведеному нижче коді програми створюється простий клас pClass, визначається об'єкт цього класу P_ob і оголошується покажчик на об'єкт типу pClass з іменем р. У наведеному прикладі показано, як можна безпосередньо отримати доступ до об'єкта P_ob і як використовувати для цього покажчик (у цьому випадку ми маємо справу з непрямим доступом).

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

class pClass { // Оголошення класового типу

int num;

public:

void setNum(int num) {num = num;}

void showNum() { cout << "num= " << num << "\n"; }

};

int main()

{

pClass P_ob, *p; // Створення об'єкта класу і покажчика на нього.

P_ob.setNum(1); // Отримуємо прямий доступ до об'єкта P_ob.

P_ob.showNum();

p = &P_ob; // Присвоюємо покажчику p адресу об'єкта P_ob.

p->showNum(); // Отримуємо доступ до об'єкта P_ob за допомогою покажчика.

cout<<"press any key!";

while(!kbhit());

}

Звернемо Вашу увагу на те, що адреса об'єкта P_ob отримується шляхом використання оператора посилання "&", що цілком відповідає механізму отриманню адреси для змінних будь-якого іншого типу.

Інкрементація або декрементація покажчика відбувається так, щоб завжди вказувати на наступний або попередній елемент базового типу. Те саме відбувається і під час інкрементації або декрементації покажчика на об'єкт: він вказуватиме на наступний або попередній об'єкт. Щоби проілюструвати цей механізм, дещо модифікуємо попередню програму. Тепер замість одного об'єкта P_ob оголосимо двоелементний масив P_ob типу pClass. Звернемо Вашу увагу на те, як інкрементується та декрементується покажчик р для доступу до двох елементів цього масиву.

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

class pClass { // Оголошення класового типу

int num;

public:

void setNum(int num) {num = num;}

void showNum(){ cout << "num= " << num << "\n"; }

};

int main()

{

pClass P_ob[2],*p;

P_ob[0].setNum(10); // Прямий доступ до об'єктів

P_ob[1].setNum(20);

p = &P_ob[0]; // Отримуємо покажчик на перший елемент.

p->showNum();// Відображаємо значення елемента P_ob[0] за допомогою покажчика.

p++; // Переходимо до наступного об'єкта.

p->showNum(); // Відображаємо значення елемента P_ob[1]// за допомогою покажчика.

p--; // Повертаємося до попереднього об'єкта.

p->showNum(); // Знову відображаємо значення елемента P_ob[0].

cout<<"press any key!";

while(!kbhit());

}2.4. Зразок виконання роботи

main.ccp

#include "stdafx.h"

#include <string>

#include <ctime>

#include <conio.h>

#include <iostream>

#include "Student.h"

using namespace std;

void main()

{

Student *spis;

int n;

cout<<"Input a number of students: "; cin>>n;

spis=new Student [n];

for(int i=0;i<n;i++) {

cout<<"=============================="<<endl;

spis[i].show();

}

spisfac(spis,n);

spisfackurs(spis,n);

delete [] spis;

cout<<"press any key!";

while(!kbhit());

}

Student.h

#pragma once

struct date // дата рождения

{ char daymon[6];

int year; };

class Student

{

char name[30];

date t;

char adr[30], fac[20];

int kurs;

public:

Student(void);

char *getfac();

int getkurs();

void show();

~Student(void);

};

void spisfac(Student spis[],int);

void spisfackurs(Student spis[],int);

Student.ccp

#include "StdAfx.h"

#include "Student.h"

#include <string>

#include <iostream>

using namespace std;

Student::Student(void)

{cout<<"Input name:"; cin>>name;

cout<<"Input date of born\n";

cout<<"Day.mon:"; cin>>t.daymon;

cout<<"Year:"; cin>>t.year;

cout<<"Input adr:"; cin>>adr;

cout<<"Input fac:"; cin>>fac;

cout<<"Input kurs:"; cin>>kurs;

}

Student::~Student(void)

{}

void Student::show()

{

cout<<"Name :"<<name<<endl;

cout<<"Was born :"<<t.daymon<<'.'<<t.year<<endl;

cout<<"Address :"<<adr<<endl;

cout<<"Fac :"<<fac<<endl;

cout<<"Kurs :"<<kurs<<endl;

}

char *Student::getfac() { return fac; }

int Student::getkurs() { return kurs; }

void spisfac(Student spis[],int n)//список студентов заданного факультетата

{ char fac[20];

cout<<"Input faculty:"; cin>>fac;

for(int i=0;i<n;i++)

if(strcmp(spis[i].getfac(),fac)==0)spis[i].show();

}

void spisfackurs(Student spis[],int n)

//список студентов заданных факультета и курса

{ int i,k;

char fac[20];

cout<<"Input faculty:"; cin>>fac;

cout<<"Input the course:"; cin>>k;

for(i=0;i<n;i++)

if ((strcmp(spis[i].getfac(),fac)==0)&&(spis[i].getkurs()==k))

spis[i].show();

}

Рис. 1. Вигляд вікна в результаті компіляції програми

Рис. 2. Діаграма класів і варіантів використання

2.5. Індивідуальні завдання

Розробити класи для описаних нижче об’єктів. Передбачити в класах методи set(), get(), show() та визначити інші методи для виконання індивідуального завдання. Дані про об’єкти вводити в форму і результат виводити також в форму.

1. Student: прізвище, ім’я, по-батькові, дата народження, адрес, телефон, факультет, курс. Створити масив об’єктів. Вивести:

а) список студентів заданого факультету;

б) список студентів для кожного факультету і курсу;

в) список студентів, які народились після певного заданого року.

2. Abiturient: прізвище, ім’я, по-батькові, адрес, оцінки. Створити масив об’єктів. Вивести:

а) список абітурієнтів, які мають незадовільні оцінки;

б) список абітурієнтів, сума балів яких є не менше заданої;

в) вибрати n абітурієнтів, які мають саму більшу суму балів.

3. Aeroflot: пункт призначення, номер рейсу, тип літака, час вильоту, дні тижня. Створити масив об’єктів. Вивести:

а) список рейсів для заданого пункту призначення;

б) список рейсів для заданого дня тижня;

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

4. Book: автор, назва, видавництво, рік, кількість сторінок. Створити масив об’єктів. Вивести:

а) список книг заданого автора;

б) список книг, які видало задане видавництво;

в) список книг, випущених після заданого року.

5. Worker: прізвище та ініціали, посада, рік прийняття на роботу, заробітна плата. Створити масив об’єктів. Вивести:

а) список робітників, стаж роботи яких на даному підприємстві перевищує задане кількість років;

б) список робітників, заробітна плата яких більше заданої;

в) список робітників, які займають вказану посаду.

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

а) список поїздів, які курсують до заданого пункту призначення;

б) список поїздів, які курсують до заданого пункту призначення і відправляються після завданої години;

в) список поїздів, які курсують до заданого пункту призначення і мають загальні місця.

7. Product: назва, виробник, ціна, термін зберігання, кількість. Створити масив об’єктів. Вивести:

а) список товарів заданої назви;

б) список товарів заданої назви, ціна яких не вища вказаної;

в) список товарів, термін зберігання яких вище вказаного.

8. Patient: прізвище, ім’я, по-батькові, адрес, номер медичної карти, діагноз. Створити масив об’єктів. Вивести:

а) список пацієнтів, які мають заданий діагноз;

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

9. Bus: прізвище та ініціали водія, номер автобуса, номер маршруту, марка, рік початку експлуатації, пробіг. Створити масив об’єктів. Вивести:

а) список автобусів для заданого номера маршруту;

б) список автобусів, які експлуатуються більше 10 років;

в) список автобусів, пробіг яких більше 10 000 км.

10. Customer: прізвище, ім’я, по-батькові, адрес, телефон, номер кредитки, номер банківського рахунку. Створити масив об’єктів. Вивести:

а) список покупців в алфавітному порядку;

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

11. File: ім’я файлу, розмір, дата створення, кількість звернень. Створити масив об’єктів. Вивести:

а) список файлів, впорядкований за алфавітом;

б) список файлів, розмір яких перевищує заданий;

в) список файлів, число звернень до яких перевищує задане.

12. Word: слово, номера сторінок, на яких зустрічається слово (від 1 до 10), число сторінок. Створити масив об’єктів. Вивести:

а) слова, які зустрічаються більше ніж на n сторінках;

б) слова а алфавітному порядку;

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

13. House: адрес, поверх, кількість кімнат, площа. Створити масив об’єктів. Вивести:

а) список квартир, що відповідає заданому числу кімнат;

б) список квартир, що має задане число кімнат і знаходиться на поверсі, розташованому в вказаному проміжку;

в) список квартир, які мають площу більшу заданої.

14. Phone: прізвище, ім’я, по-батькові, адрес, номер, час міжміських розмов, час міжнародних розмов. Створити масив об’єктів. Вивести:

а) дані про абонента, час міжміських розмов якого перевищує заданий;

б) дані про абонентів, які скористались міжнародними переговорами;

в) дані про абонентів в алфавітному порядку.

15. Person: прізвище, ім’я, по-батькові, адрес, стать, освіта, рік народження. Створити масив об’єктів. Вивести:

а) список осіб, вік яких перевищує заданий;

б) список осіб з вищою освітою;

в) список осіб чоловічої статі.

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

1. Для чого потрібні класи?

2. Що визначають методи класу?

3. Якими типами можуть бути атрибути класу?

4. Який за замовчуванням доступ до елементів структури?

5. Яка відмінність між С++-класами і С++-структурами?

6. Чому об'єднання і класи називають спорідненими типами?

7. Наведіть способи створення вбудовуваних функцій.

8. Як створити масиви об'єктів?

9. Як відбувається ініціалізація масивів об'єктів?

10. Які основні принципи ООП Ви знаєте? Що вони означають?

Лабораторна робота №3. Робота з конструкторами та перевантаження методів класу

МЕТА РОБОТИ: освоїти поняття констуктора, його призначення. Навчитись перевантажувати методи класу, здобути навики роботи з ними.

3.1. Програма роботи

3.1.1 Отримати завдання.

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

3.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

3.1.4. Оформити електронний звіт про роботу та захистити її.

3.2. Вказівки до виконання роботи

3.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 3.5 і записує його до звіту.

3.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 3.4.

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

3.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

3.3. Теоретичні відомості

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

  • конструктор не повертає значення, навіть типу void. Неможливо отримати вказівник на конструктор;

  • клас може мати декілька конструкторів з різними параметрами для різних видів ініціалізації (при цьому використовується механізм перевантаження);

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

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

  • конструктори не наслідуються;

  • конструктори не можна описувати з модифікаторами const, virtual, static;

  • конструктори глобальних об’єктів викликаються до функції main. Локальні об’єкти створюються, як тільки стає активною їх область дії;

  • Конструктор викликається автоматично при створенні об’єкта.

Незважаючи на виконання конструкторами унікальних дій, проте вони не сильно відрізняються від функцій інших типів і також можуть піддаватися перевантаженню. Щоб перевантажувати конструктор класу, достатньо оголосити його в усіх потрібних форматах і визначити кожну дію, пов'язану з відповідним форматом. Наприклад, у наведеному нижче коді програми оголошено клас timerClass, який діє як таймер зворотного відліку. Під час створення об'єкта типу timerClass таймеру присвоюється деяке початкове значення часу. Під час виклику функції run(), таймер виконує рахунок в зворотному порядку до нуля, а потім подає звуковий сигнал. У наведеному прикладі конструктор перевантажується тричі, надаючи тим самим можливість задавати час як у секундах (причому або числом, або рядком), так і в хвилинах і секундах (за допомогою двох цілочисельних значень). У цій програмі використовується стандартна бібліотечна функція clock(), яка повертає кількість сигналів, прийнятих від системного годинника з моменту початку виконання програми. Ось як виглядає прототип цієї функції:

chas_t clock();

Тип chas_t є різновидом довгого цілочисельного типу. Операція ділення значення, що повертається функцією clock(), на значення CLOCKS_PER_SEC дає змогу перетворити отриманий результат в секунди. Як прототип для функції clock(), так і визначення константи CLOCKS_PER_SEC належать заголовку <ctime>.

Демонстрація використання перевантажених конструкторів

#include <iostream> // Для потокового введення/виведення

#include <cstdlib> // Для використання бібліотечних функцій

#include <ctime> // Для використання системного часу і дати

using namespace std; // Використання стандартного простору імен

class timerClass {

int seconds;

public:

// Задавання секунд у вигляді рядка

timerClass(char *t) { seconds = atoi(t);}

// Задавання секунд у вигляді цілого числа

timerClass(int t) { seconds = t;}

// Час, що задається в хвилинах і секундах

timerClass(int xv, int sec) { seconds = xv*60 + sec;}

void run();

};

void timerClass::run()

{

chas_t t1;

t1 = clock();

while((clock()/CLOCKS_PER_SEC – t1/CLOCKS_PER_SEC)< seconds);

cout << "\a"; // Подання звукового сигналу

}

int main()

{

timerClass A_ob(10), B_ob("20"), C_ob(1, 10);

A_ob.run(); // відлік 10 секунд

B_ob.run(); // відлік 20 секунд

C_ob.run(); // відлік 1 хвилини і 10 секунд

}

Під час створення у функції main() об'єктів A_ob, B_ob і C_ob класу timerClass він надає початкові значення трьома різними способами, що підтримуються перевантаженими функціями конструкторів. У кожному випадку викликається конструктор, який відповідає заданому переліку параметрів і тому належним чином ініціалізує "свій" об'єкт.

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

Приклад викорсистання перезавантаження конструкторів та методів класу можна проілюструвати на прикладі програми, яка імітує «випечення пиріжків». Тут використовується конструктор трьох типів: без параметрів – CakeWithJam ();, з параметром типу string – CakeWithJam (string), та з параметром типу об’єкт класу – CakeWithJam (CakeWithJam&);. Пера завантаженим методом є «відкусування» – Bite (float); та повернення частини пиріжка, що залишився – string Bite (const CakeWithJam&);.

Діаграму класів створеної програми зображено на рис.1.

Файл main.cpp

#include "stdafx.h"

#include <iostream>

#include "CakeWithJam.h"

using namespace std;

int main(array<System::String ^> ^args)

{

CakeWithJam a, b("Chornuchnum djemom");

b.Swallow();

CakeWithJam *x = new CakeWithJam();

cout << x->Bite(0.2) << endl;

cout << x->Bite(0.8) << endl;

delete x;

CakeWithJam *y = new CakeWithJam("Polunychnum djemom ");

cout << y->Bite(0.5) << endl;

cout << x->Bite(0.5) << endl;

delete y;

cout << a.Bite(b) << endl;

cout << ("Dodatu djem v " )<< a << endl;

cin >> a;

CakeWithJam::UseJamByDefault("Polunyceju");

CakeWithJam c;

cout << "Novyj djem " << c << endl;

c.UseJamByDefault("Chornuceju");

CakeWithJam d;

cout << "Inshuj novuj djem " << d << endl;

cin>>a;

return 0;

}

Файл CakeWithJam.h

#pragma once

#include <iostream>

#include <iomanip>

#include <string>

#include <conio.h>

using namespace std;

class CakeWithJam

{

float Fraction;

string NameOfJamInside;

public:

void Swallow (void);

string Bite (float);

string Bite (const CakeWithJam&);

CakeWithJam ();

CakeWithJam (string);

~CakeWithJam ();

CakeWithJam (CakeWithJam&);

friend ostream& operator<<(ostream&,CakeWithJam&);

friend istream& operator>>(istream&,CakeWithJam&);

static string NameOfJamByDefault;

static void UseJamByDefault(const string);

};

Файл CakeWithJam.cpp

#include "stdafx.h"

#include <iostream>

#include <iomanip>

#include <string>

#include <conio.h>

#ifndef _CakeWithJam_h_

#define _CakeWithJam_h_

#include "CakeWithJam.h"

#endif

using namespace std;

void CakeWithJam::Swallow (void)

{

Fraction = 0.0;

cout <<(":-O Pyrizhok z ")<< NameOfJamInside;cout <<(" zjilu!!!")<< endl;

}

string CakeWithJam::Bite (float BiteFraction)

{

Fraction -= BiteFraction;

if(Fraction>=0.7) return ("Vkysitj biljshe, djem sche vsereduni!!!");

else if(Fraction>0.3) return NameOfJamInside;

else if(Fraction>0.0) return ("Chomy tak malo vkysulu? Djemy zliva nema!!!");

else if(Fraction==0.0) { Swallow(); return ("Vu zjilu djem!!!"); }

else return ("Vse dobre! Ne zaburajte v mene chasy!!!");

}

CakeWithJam::CakeWithJam ()

{

Fraction = 1.0;

NameOfJamInside = NameOfJamByDefault;

cout <<("Novuj purizhok z ")<< NameOfJamInside; cout <<(" specheno!!!")<< endl;

}

CakeWithJam::CakeWithJam (string jam)

{

Fraction = 1.0; NameOfJamInside = jam;

cout <<("Novuj purizhok z ")<< NameOfJamInside;cout<<("specheno!")<< endl;

}

CakeWithJam::~CakeWithJam ()

{

cout <<("Pyrizhok z ")<< NameOfJamInside;

if(Fraction>0.0) cout <<(" ne zjilu!")<< endl;

else cout <<(" zjilu!")<< endl;

}

CakeWithJam::CakeWithJam (CakeWithJam& srcObj)

{

Fraction = srcObj.Fraction;

NameOfJamInside = srcObj.NameOfJamInside;

cout << ("Novuj purizhok z ") << NameOfJamInside;cout << ("specheno!") << endl;

}

string CakeWithJam::Bite (const CakeWithJam& srcObj)

{

return this->Bite(1-srcObj.Fraction);

}

ostream& operator<<(ostream& os, CakeWithJam& cake) {

return os << ("Purizhok ") << cake.NameOfJamInside;cout << (" djemom (" )<< cake.Fraction;cout << (" zliva)");

}

istream& operator>>(istream& is, CakeWithJam& cake)

{

string s;

is >> s;

if(cake.Fraction>=1.0)

if(cake.NameOfJamInside.empty()) cake.NameOfJamInside = s;

else cake.NameOfJamInside += ((" i ") + s);

return is;

}

void CakeWithJam::UseJamByDefault(const string jam)

{

NameOfJamByDefault = jam;

}

string CakeWithJam::NameOfJamByDefault = ("jablukom");

Рис. 1. Діаграма класів

3.4. Розширений опис завдання

Створити клас та описати 3–4 перевантажені методи згідно індивідуального завдання.

Деталізація завдання

1. Частина 1. «Створення класу»

1.1. Описати клас згідно індивідуального завдання, обов’язково створивши у

ньому:

1.1.1. принаймні по одному відкритому (public), закритому (private) та

захищеному (protected) полю;

1.1.2. конструктор по замовчуванню, конструктор з параметрами;

1.1.3. деструктор;

1.1.4. відкриті (public) методи-аксесори для читання та запису закритих та

захищених полів;

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

1.1.6. власні поля та методи, що дозволяють розширити можливості класу відповідно до тематики індивідуального завдання;

1.1.7. метод виводу екземпляру класу на екран;

1.1.8. консольний метод ініціалізації екземпляру класу (вводу з клавіатури);

1.2. У головній програмі:

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

1.2.2. продемонструвати звертання до полів екземпляру класу та використання методів-аксесорів;

1.2.3. створити посилання на екземпляр класу через вказівник та продемонструвати використання полів та методів класу через цей вказівник на екземпляр класу;

1.2.4. динамічно створити (new) екземпляр класу, зберігши його адресу у раніше описаному вказівнику, продемонструвати роботу з ним та видалити (delete);

1.2.5. продемонструвати роботу з усіма додатково створеними полями та методами;

1.2.6. продемонструвати роботу з усіма описаними методами вводу/виводу класу.

2. Частина 2. «Перевантаження методів класу»

2.1. Описати клас із частини 1 з перевантаженим методом відповідно до індивідуального завдання.

2.2. У головній програмі проілюструвати роботу перевантажених методів.

3.5. Індивідуальні завдання

1. Клас «Торт» з полями:

  • назва (public);

  • крем (private);

  • вітальний напис (protected);

  • кількість шматків

  • вага;

  • ціна за 1кг;

  • вартість доставки

За допомогою методів класу передбачити наступні можливості:

  • зміна назви;

  • обчислення вартості торту;

  • зміну ціни торту, якщо назва відповідає заданій;

Перевантажені методи:

  • розрізання — з одним параметром (ціле число) — встановлює кількість шматківна скільки необхідно ділити торт; якщо не передано ні одного параметра – повертає зменшує кількість відрізаних частин на одиницю.

  • встановлення вартості доставки: без параметрів – встановлює вартість доставки рівну 0; якщо предано один цілий параметр с – обчислює вартість доставки як с*20.

2. Клас «Квітка» з полями:

  • назва (public),

  • кількість пелюсток (private),

  • колір (protected);

  • місяць цвітіння;

  • висота;

  • тип суцвіття;

  • тип кореневої системи.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • вивід всієї інформаціїї про об’єкт;

  • вивід всіх квітів, висота яких більша за вказану;

  • вивід всіх квітів, назва яких починається з певної букви;

Перевантажений метод:

місяць цвітіння — числовий або текстовий параметр — встановлює місяць цвітіння квітки, якщо передано один параметр якогось із двох типів; повертає текстове значення місяця цвітіння квітки, якщо не передано ні одного параметра.

3. Клас «Птах» з полями:

  • назва (public);

  • кількість пташенят (private);

  • вага (protected);

  • висота польоту;

  • колір;

  • розмах крил;

  • батьківщина.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • виведення всіх птахів, розмах крил яких я більше заданого;

  • пошук пташки, що літає найвище;

  • пошук птахів, вага яких знаходиться у певному діапазоні.

Перевантажений метод висота польоту:

  • 1 цілий параметр – встановлює максимально допустиму висоту польоту;

  • Цілий та рядковий параметр, що вказує одиниці виміру (метри або кілометри) – встановлює максимально допустиму висоту;

  • Без параметрів – повертає максимально допустиму висоту польоту у вигляді стрічки із зазначенням висоти та одиниць виміру.

4. Клас «Коробка» з полями:

  • назва (public);

  • форма (private);

  • матеріал (protected);

  • структура «адреса доставки» з полями вулиця, будинок, квартира;

  • вартість доставки;

  • форма оплати;

За допомогою методів класу передбачити наступні можливості:

  • виведення адреси доставки;

  • зміна вартості доставки;

  • зміна назви;

Перевантажені методи:

  • адреса доставки — з одним, двома або трьома параметрами (вулиця — текст, будинок, квартира — цілі числа) — встановлює адресу доставки, якщо передано хоча б якісь параметри (припускається, що номер квартири та номер будинку по замовчуванню рівні одиниці); повертає адресу доставки у вигляді структури з трьома полями, якщо не передано ні одного параметра.

  • форма оплати – якщо передано один цілий параметр встановлює форму оплати як готівкову, якщо передано 2 параметри (ціле, ціле) – встановлює форму оплати як безготівкому, причому перший параметр слугує номером картки.

5. Клас «Військовий» з полями:

  • ім’я (public);

  • строк служби (private);

  • звання (protected);

  • структура дата народження;

  • номер телефону;

  • номер частини;

  • рід військ;

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • пошук всіх осіб певного звання;

  • пошук осіб, строк служби яких знаходится у заданому діапазоні;

  • зніна заданого номеру телефону;

Перевантажений метод: місце служби — з одним або двома параметрами (рід військ — текст, номер частини — ціле число) — повертає текстову стрічку (рід військ), якщо передано правильний номер частини, або порожню стрічку, якщо номер частини помилковий для даного військовослужбовця; аналогічно повертає номер частини або нуль, якщо передано один текстовий параметр (рід військ); встановлює нове місце служби, якщо передано два параметри.

6. Клас «Сховище» з полями

  • назва (public);

  • предмети (private);

  • тип (protected);

  • інвентарний номер;

  • адреса;

  • вага предмету.

За допомогою методів класу передбачити наступні можливості:

  • переміщення предмета з одного сховища у інше (зміна адреси)

  • вивід предметів, що містяться у сховищі, назва яких починається на певну букву;

  • сортування предметів у сховищі згідно лексикографічної послідовності.

Перевантажений метод: зберігання — з одним параметром (інвентарний номер — ціле число, або назва предмету — текст) — повертає номер місця зберігання, якщо одержано інвентарний номер, або записує новий предмет на склад, якщо передано назву предмету (при цьому предмету призначається місце та інвентарний номер) у масив «предмети».

7. Клас «Планета» з полями:

  • назва (public);

  • супутники (private);

  • діаметр (protected);

  • відстань до Сонця;

  • маса;

  • відстань до супутників;

  • маса супутників.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • вивід планет у послідовності згідно з відстанню до сонця;

  • пошук планет із найбільшою кількістю супутників;

  • пошук найбільшою за масою об’єкта (маса планети + маси всіх супутників).

Перевантажений метод: супутник — з двома параметрами (номер — ціле число, віддаль — дійсне число) — повертає номер супутника, якщо передано один дійсний параметр, повертає віддаль, якщо передано цілий параметр, встановлює нове значення віддалі, якщо передано обидва параметри.

8. Клас «Таксі» з полями:

  • пасажир (public);

  • водії (private);

  • адреси (protected);

  • марка автомобіля;

  • пасажиромісткість автомобіля;

  • державний номер;

  • вартість замовлення.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • підрахунок автомобілів певної марки;

  • пошук автомобіля за параметром „кількість пасажирів”;

  • встановлення знижки.

Перевантажений метод: замовлення — з одним параметром (адреса – текст), з двома параметрами (водій – ціле число, адреса – текст), або без параметрів — повертає ціле число (номер водія, призначеного на виклик), якщо передано один параметр; повертає true/false, як відповідь на можливість замовити конкретного водія за заданою адресою, якщо передано два параметри; повертає співвідношення вільних та замовлених водіїв (дійсне число), якщо викликано без параметрів. При формуванні замовлення поле «пасажир» використовується для ідентифікації замовника — припускається, що замовник повинен записати у це поле своє прізвище і тоді викликати метод «замовлення».

9. Клас «Порт» з полями:

  • назва (public);

  • площа (private);

  • кількість населення (protected);

  • тип (річковий, морський або проміжний);

  • кількість кораблів, що щоденно можуть обслуговуватись;

  • кількість кораблів, що можуть обслуговуватись одночасно;

  • відстань до найближчого порту;

  • назва найближчого порту;

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • сортування портів за кількістю населення;

  • пошук найбільшого за площею порту;

  • перевірка можливості обслуговування певної кількості кораблів за 1 день (якщо неможливо, то виводити скільки днів необхідно).

Перевантажений метод: відстань до найближчого порту:

*цілий числовий параметр(означає, что відстань задана в кілометрах)

*цілий числовий параметр, текстовий параметр, що вказує довжину та одиниці їх виміру одиниці виміру (метри або милі).

10. Клас «Країна» з полями:

  • назва (public);

  • столиця (private);

  • кількість населення (protected);

  • площа;

  • сусіди;

  • наявність виходу в море;

  • середня заробітна плата;

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • підрахунок кількості сусідів;

  • сортування за назвою;

  • сортування за столицею;

Перевантажений метод: відстань до найближчої столиці:

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

*цілий числовий параметр, текстовий параметр, що вказує відстань(цілий параметр) і тип траспорту (текстовий) – літак, поїзд, корабель.

*текстовий, цілий – встановлює нове значення відстані сполученням певним видом транспорту

11. Клас «Фотоапарат» з полями:

  • марка (public);

  • тип матриці (private);

  • чутливість матриці (protected);

  • модель;

  • діагональ екрану;

  • об’єм накопичувача;

  • фото (містить назву, тип і розмір).

За допомогою методів класу передбачити наступні можливості:

  • пошук найбільшого фото за розміром;

  • обчислення кількості збережених фото;

Перевантажений метод: збереження фото — без параметрів – нарощує кількість фото на 1; з одним параметром (розмір однієї фотографії) — повертає максимальну кількість фото, що можуть бути вміщені на карту памяті, з двома параметрами (кількість фото та їх розмір) ­– повертає значення типу bool, яке вказує, чи достатньо місця на карті пам’яті для розміщення даних фото.

12. Клас «Квартира» з полями:

  • забудовник (public);

  • кількість кімнат (private);

  • матеріал будинку (protected);

  • тип (люкс, стандарт, бюджет);

  • площа;

  • вартість 1м.кв.;

  • адреса;

  • поверх.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • пошук усіх квартир певного типу;

  • пошук найбільшої за площею квартири;

  • пошук квартир на заданому поверсі.

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

13. Клас «Автомобіль» з полями:

  • марка (public);

  • об’єм двигуна (private);

  • колір (protected);

  • кількість місць;

  • тип (седан, хетчбек, кабріолет);

  • максимальна швидкість;

  • ціна;

  • рік випуску.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • пошук всіх автомобілів певного типу;

  • пошук „найстаршого” автомобіля;

  • пошук авто певного цінового діапазону.

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

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

1. Що таке механізм перевантаження?

2. Назвіть причини необхідності перевантаження конструкторів?

3. Як можна перевантажити метод класу?

4. Який за замовчуванням доступ до елементів структури?

5. Чи може бути конструктор класу бути порожнім, обґрунтуйте свою думку.

6. Що таке деструктор класу, коли він викликається?

7. Опишіть створення перевантажених методів та конструкторів класу.

8. Якщо змінити порядок слідування параметрів у методі, чи необхідно створювати відповідний перевантажений метод? Чому?

9. Чи може бути у класі перевантажений деструктор? Чому?

10. Які основні принципи ООП Ви знаєте? Що вони означають?

Лабораторна РОБОТА №4. Перевантаже ння операторів для класу

МЕТА РОБОТИ: засвоїти механізм перевантаження операторів та здобути практичні навики при роботі з ними.

4.1. Програма роботи

4.1.1 Отримати завдання.

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

4.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

4.1.4. Оформити електронний звіт про роботу та захистити її.

4.2. Вказівки до виконання роботи

4.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 4.5 і записує його до індивідуального бланку.

4.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 4.4.

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

4.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

4.3. Теоретичні відомості

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

Перевантаження операцій здійснюється за допомогою методів спеціального виду (функцій-операцій) і підлягає наступним правилам:

  • при перевантаженні операцій зберігаються кількість аргументів, пріоритети операцій і правила асоціації (справа наліво і зліва направо), що використовуються в стандартних типах;

  • для стандартних типів даних перевизначити операції неможливо;

  • функції-операції не можуть мати аргументів по замовчуванню;

  • функції-операції не наслідуються (за виключенням =);

  • функції-операції не можуть визначатися як static.

Функцію-операцію можна визначити трьома способами:

  • вона може бути методом класу;

  • вона може бути дружньою функцією;

  • вона може бути звичайною функцією.

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

Функція-операція містить ключове слово operator, за яким слідє знак перевизначеної операції:

тип operator операція (список параметрів) { тіло функції }

Перевантаження унарних операцій:

Унарні операції – це такі, які мають тільки один операнд (операнд – це змінна, на яку діє операція). Прикладом унарних операцій є операціїї інкремента та декремента «++» та «--» а також унарний мінус, наприклад -35.

Для демонстрації перевантаження унарного оператора створима клас Counter, який міститиме два поля: hours ті minutes, що визначатимуть деякий час доби. У класі створено 2 конструктори: без параметрів (поточний час встановлюється рівним 0год 00хв) та параметризований, з можливістю задати певний час. Унарні оператори інкременту та декременту моделюватимуть перевід годинника на літній чи зимовий час.

Counter.h

#pragma once

class Counter

{

unsigned int hours;

unsigned int minutes;

public:

Counter(); //конструктор без параметрів

Counter(int,int); //параметизований конструктор

~Counter(void);

unsigned int get_hours(); //метод повернення кількості годин

unsigned int get_minutes();//метод повернення кількості хвилин

void out_counter(); //вивід на консоль обєкту

Counter operator++ (); //Перевантажена операція інкремента

Counter operator-- (); //Перевантажена операція декремента

Counter operator+ (Counter); //Перевантажена операція суми

};

Counter.cpp

#include "StdAfx.h"

#include <iostream>

#include "Counter.h"

Counter::Counter(){

hours=0;

minutes=0;

}

Counter::Counter(int h,int m){

hours=h;

minutes=m;

}

unsigned int Counter::get_hours(){

return hours;

}

unsigned int Counter::get_minutes(){

return minutes;

}

Counter Counter::operator++(){

++hours;

if (hours>=24) hours-=24;

return Counter(hours,minutes);

}

Counter Counter::operator--(){

if (hours==0) hours+=24;

--hours;

return Counter(hours,minutes);

}

void Counter::out_counter(){

std::cout<<hours<<"h "<<minutes<<"m\n";

}

Counter::~Counter(void){

}

Counter Counter::operator+ (Counter t2){

int h,m;

h=hours+t2.hours;

m=minutes+t2.minutes;

if (m>=60) {m-=60; h++;}

if (h>=24) {h-=24;}

return Counter(h,m);

}

main.cpp

#include "stdafx.h"

#include "Counter.h"

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{

Counter c1(10,20);

Counter c2;

cout<<"Do Perevedennja "<<"\n";

c1.out_counter();

c2.out_counter();

cout<<"Pislja perevedennja pershogo godunnuka vpered"<<"\n";

++c1;

c1.out_counter();

c2.out_counter();

cout<<"Pislja perevedennja drygogo godunnuka nazad"<<"\n";

--c2;

c1.out_counter();

c2.out_counter();

c3=c1+c2;

cout<<"Vid"<<"\n";

c1.out_counter();

cout<<"Cherez"<<"\n";

c2.out_counter();

cout<<"Byde"<<"\n";

c3.out_counter();

cin>>q;

return 0;

}

Перевантаження бінарних операцій.

Бінарні операції можуть бути перевантажені таким же чином, як і унарні. У наведеному вище коді перевантажена операція «+», а у головному коді зустрічається стрічка, де проводиться сумування двох об’єктів (c3=c1+c2). Оголошення в класі Counter виглядає наступним чином:

Counter operator+ (Counter);

Ця операція повертає значення типу Counter і приймає один аргумент того ж типу.

Для обчислення значення функції operator+ ми спочатку додаємо значення hours та minutes обох операндів (коректуючи їх в разі необхідності). Отримані значення h та m ми згодом використовуємопри ініціалізації безіменного об’єкту Counter, який буде повертати значення:

return Counter(h,m);

У виразі

c3=c1+c2;

важливо розуміти, до яких об’єктів будуть відноситись аргументи і значення, що повертаються. Коли компілятор зустріне цей вираз, то він переглядає типи аргументів, знайшовши тільки аргументи типу Counter, він виконає операції класу Counter operator+ (Counter);. Але який із об’єктів використовується в якості аргумента – с1 чи с2? І чи немає потреби використовувати два аргументи, оскільки ми додаєма 2 об’єкти?

Існує правило: об’єкт, що розташований зліва сторони операції (у нашому випадку с1), викликає функцію оператора. Об’єкт, що стоїть справа знака операції повинен бути переданий у функцію в якості аргумента. Операція повертає значення, яке ми згодом використовуємо для власних потреб. У функції до лівого операнда ми маємо прямий доступ, використовуючи hours та minutes, так як це об’єкт, що викликав функцію. До правого операнда ми маємо доступ як до аргумента функції, тобто t2.hours та t2.minutes.

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

4.4. Розширений опис завдання

Створити клас та описати 3–4 перевантажені методи згідно індивідуального завдання.

Деталізація завдання

1. Частина 1. «Створення класу»

1.1. Описати клас згідно індивідуального завдання, обов’язково створивши у

ньому:

1.1.1. принаймні по одному відкритому (public), закритому (private) та

захищеному (protected) полю;

1.1.2. конструктор по замовчуванню, конструктор з параметрами;

1.1.3. деструктор;

1.1.4. відкриті (public) методи-аксесори для читання та запису закритих та

захищених полів;

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

1.1.6. власні поля та методи, що дозволяють розширити можливості класу відповідно до тематики індивідуального завдання;

1.1.7. метод виводу екземпляру класу на екран;

1.1.8. консольний метод ініціалізації екземпляру класу (вводу з клавіатури);

1.2. У головній програмі:

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

1.2.2. продемонструвати звертання до полів екземпляру класу та використання методів-аксесорів;

1.2.3. створити посилання на екземпляр класу через вказівник та продемонструвати використання полів та методів класу через цей вказівник на екземпляр класу;

1.2.4. динамічно створити (new) екземпляр класу, зберігши його адресу у раніше описаному вказівнику, продемонструвати роботу з ним та видалити (delete);

1.2.5. продемонструвати роботу з усіма додатково створеними полями та методами;

1.2.6. продемонструвати роботу з усіма описаними методами вводу/виводу класу.

2. Частина 2. «Перевантаження методів класу»

2.1. Описати клас із частини 1 з перевантаженим методом відповідно до індивідуального завдання.

2.2. У головній програмі проілюструвати роботу перевантажених методів.

4.5. Індивідуальні завдання

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

1. Клас «Торт» з полями:

  • назва (public);

  • крем (private);

  • вітальний напис (protected);

  • кількість шматків

  • вага;

  • ціна за 1кг;

  • вартість доставки

За допомогою методів класу передбачити наступні можливості:

  • зміна назви;

  • обчислення вартості торту;

  • зміну ціни торту, якщо назва відповідає заданій;

Перевантажені методи:

  • розрізання — з одним параметром (ціле число) — встановлює кількість шматківна скільки необхідно ділити торт; якщо не передано ні одного параметра – повертає зменшує кількість відрізаних частин на одиницю.

  • встановлення вартості доставки: без параметрів – встановлює вартість доставки рівну 0; якщо предано один цілий параметр с – обчислює вартість доставки як с*20.

2. Клас «Квітка» з полями:

  • назва (public),

  • кількість пелюсток (private),

  • колір (protected);

  • місяць цвітіння;

  • висота;

  • тип суцвіття;

  • тип кореневої системи.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • вивід всієї інформаціїї про об’єкт;

  • вивід всіх квітів, висота яких більша за вказану;

  • вивід всіх квітів, назва яких починається з певної букви;

Перевантажений метод:

місяць цвітіння — числовий або текстовий параметр — встановлює місяць цвітіння квітки, якщо передано один параметр якогось із двох типів; повертає текстове значення місяця цвітіння квітки, якщо не передано ні одного параметра.

3. Клас «Птах» з полями:

  • назва (public);

  • кількість пташенят (private);

  • вага (protected);

  • висота польоту;

  • колір;

  • розмах крил;

  • батьківщина.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • виведення всіх птахів, розмах крил яких я більше заданого;

  • пошук пташки, що літає найвище;

  • пошук птахів, вага яких знаходиться у певному діапазоні.

Перевантажений метод висота польоту:

  • 1 цілий параметр – встановлює максимально допустиму висоту польоту;

  • Цілий та рядковий параметр, що вказує одиниці виміру (метри або кілометри) – встановлює максимально допустиму висоту;

  • Без параметрів – повертає максимально допустиму висоту польоту у вигляді стрічки із зазначенням висоти та одиниць виміру.

4. Клас «Коробка» з полями:

  • назва (public);

  • форма (private);

  • матеріал (protected);

  • структура «адреса доставки» з полями вулиця, будинок, квартира;

  • вартість доставки;

  • форма оплати;

За допомогою методів класу передбачити наступні можливості:

  • виведення адреси доставки;

  • зміна вартості доставки;

  • зміна назви;

Перевантажені методи:

  • адреса доставки — з одним, двома або трьома параметрами (вулиця — текст, будинок, квартира — цілі числа) — встановлює адресу доставки, якщо передано хоча б якісь параметри (припускається, що номер квартири та номер будинку по замовчуванню рівні одиниці); повертає адресу доставки у вигляді структури з трьома полями, якщо не передано ні одного параметра.

  • форма оплати – якщо передано один цілий параметр встановлює форму оплати як готівкову, якщо передано 2 параметри (ціле, ціле) – встановлює форму оплати як безготівкому, причому перший параметр слугує номером картки.

5. Клас «Військовий» з полями:

  • ім’я (public);

  • строк служби (private);

  • звання (protected);

  • структура дата народження;

  • номер телефону;

  • номер частини;

  • рід військ;

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • пошук всіх осіб певного звання;

  • пошук осіб, строк служби яких знаходится у заданому діапазоні;

  • зніна заданого номеру телефону;

Перевантажений метод: місце служби — з одним або двома параметрами (рід військ — текст, номер частини — ціле число) — повертає текстову стрічку (рід військ), якщо передано правильний номер частини, або порожню стрічку, якщо номер частини помилковий для даного військовослужбовця; аналогічно повертає номер частини або нуль, якщо передано один текстовий параметр (рід військ); встановлює нове місце служби, якщо передано два параметри.

6. Клас «Сховище» з полями

  • назва (public);

  • предмети (private);

  • тип (protected);

  • інвентарний номер;

  • адреса;

  • вага предмету.

За допомогою методів класу передбачити наступні можливості:

  • переміщення предмета з одного сховища у інше (зміна адреси)

  • вивід предметів, що містяться у сховищі, назва яких починається на певну букву;

  • сортування предметів у сховищі згідно лексикографічної послідовності.

Перевантажений метод: зберігання — з одним параметром (інвентарний номер — ціле число, або назва предмету — текст) — повертає номер місця зберігання, якщо одержано інвентарний номер, або записує новий предмет на склад, якщо передано назву предмету (при цьому предмету призначається місце та інвентарний номер) у масив «предмети».

7. Клас «Планета» з полями:

  • назва (public);

  • супутники (private);

  • діаметр (protected);

  • відстань до Сонця;

  • маса;

  • відстань до супутників;

  • маса супутників.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • вивід планет у послідовності згідно з відстанню до сонця;

  • пошук планет із найбільшою кількістю супутників;

  • пошук найбільшою за масою об’єкта (маса планети + маси всіх супутників).

Перевантажений метод: супутник — з двома параметрами (номер — ціле число, віддаль — дійсне число) — повертає номер супутника, якщо передано один дійсний параметр, повертає віддаль, якщо передано цілий параметр, встановлює нове значення віддалі, якщо передано обидва параметри.

8. Клас «Таксі» з полями:

  • пасажир (public);

  • водії (private);

  • адреси (protected);

  • марка автомобіля;

  • пасажиромісткість автомобіля;

  • державний номер;

  • вартість замовлення.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • підрахунок автомобілів певної марки;

  • пошук автомобіля за параметром „кількість пасажирів”;

  • встановлення знижки.

Перевантажений метод: замовлення — з одним параметром (адреса – текст), з двома параметрами (водій – ціле число, адреса – текст), або без параметрів — повертає ціле число (номер водія, призначеного на виклик), якщо передано один параметр; повертає true/false, як відповідь на можливість замовити конкретного водія за заданою адресою, якщо передано два параметри; повертає співвідношення вільних та замовлених водіїв (дійсне число), якщо викликано без параметрів. При формуванні замовлення поле «пасажир» використовується для ідентифікації замовника — припускається, що замовник повинен записати у це поле своє прізвище і тоді викликати метод «замовлення».

9. Клас «Порт» з полями:

  • назва (public);

  • площа (private);

  • кількість населення (protected);

  • тип (річковий, морський або проміжний);

  • кількість кораблів, що щоденно можуть обслуговуватись;

  • кількість кораблів, що можуть обслуговуватись одночасно;

  • відстань до найближчого порту;

  • назва найближчого порту;

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • сортування портів за кількістю населення;

  • пошук найбільшого за площею порту;

  • перевірка можливості обслуговування певної кількості кораблів за 1 день (якщо неможливо, то виводити скільки днів необхідно).

Перевантажений метод: відстань до найближчого порту:

*цілий числовий параметр(означає, что відстань задана в кілометрах)

*цілий числовий параметр, текстовий параметр, що вказує довжину та одиниці їх виміру одиниці виміру (метри або милі).

10. Клас «Країна» з полями:

  • назва (public);

  • столиця (private);

  • кількість населення (protected);

  • площа;

  • сусіди;

  • наявність виходу в море;

  • середня заробітна плата;

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • підрахунок кількості сусідів;

  • сортування за назвою;

  • сортування за столицею;

Перевантажений метод: відстань до найближчої столиці:

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

*цілий числовий параметр, текстовий параметр, що вказує відстань(цілий параметр) і тип траспорту (текстовий) – літак, поїзд, корабель.

*текстовий, цілий – встановлює нове значення відстані сполученням певним видом транспорту

11. Клас «Фотоапарат» з полями:

  • марка (public);

  • тип матриці (private);

  • чутливість матриці (protected);

  • модель;

  • діагональ екрану;

  • об’єм накопичувача;

  • фото (містить назву, тип і розмір).

За допомогою методів класу передбачити наступні можливості:

  • пошук найбільшого фото за розміром;

  • обчислення кількості збережених фото;

Перевантажений метод: збереження фото — без параметрів – нарощує кількість фото на 1; з одним параметром (розмір однієї фотографії) — повертає максимальну кількість фото, що можуть бути вміщені на карту памяті, з двома параметрами (кількість фото та їх розмір) ­– повертає значення типу bool, яке вказує, чи достатньо місця на карті пам’яті для розміщення даних фото.

12. Клас «Квартира» з полями:

  • забудовник (public);

  • кількість кімнат (private);

  • матеріал будинку (protected);

  • тип (люкс, стандарт, бюджет);

  • площа;

  • вартість 1м.кв.;

  • адреса;

  • поверх.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • пошук усіх квартир певного типу;

  • пошук найбільшої за площею квартири;

  • пошук квартир на заданому поверсі.

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

13. Клас «Автомобіль» з полями:

  • марка (public);

  • об’єм двигуна (private);

  • колір (protected);

  • кількість місць;

  • тип (седан, хетчбек, кабріолет);

  • максимальна швидкість;

  • ціна;

  • рік випуску.

Створити масив об’єктів, та за допомогою методів класу передбачити наступні можливості:

  • пошук всіх автомобілів певного типу;

  • пошук „найстаршого” автомобіля;

  • пошук авто певного цінового діапазону.

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

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

1. Що таке механізм перевантаження оператора?

2. Назвіть причини необхідності перевантаження операторів?

3. Як можна перевантажити оператор для класу?

5. Які оператори перевантажувати не можна?

6. Яка різниця між перевантаженням бінарних та унарних операторів?

7. Опишіть синтаксис перевантаження унарних операторів класу.

8. У чому полягає специфіка перевантаження операторів зсуву

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

Лабораторна робота №5. одинарне Успадкування

МЕТА РОБОТИ: засвоїти основні принципи та поняття успадкування, здобути практичні навики при роботі з «батьківськими» та «нащадковими» класами.

5.1. Програма роботи

5.1.1 Отримати завдання.

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

5.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

5.1.4. Оформити електронний звіт про роботу та захистити її.

5.2. Вказівки до виконання роботи

5.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання.

5.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано

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

5.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

5.3. Теоретичні відомості

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

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

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

Спадковість – це механізм отримання нового класу з існуючих шляхом запозичення структурної або функціональної частини одного або декількох інших. Відповідно розрізняють одиночне та множинне успадкування. Спадковість створює таку ієрархію абстракцій, у якій підкласи (класи-нащадки) успадковують будову і поведінку одного або декількох суперкласів (базових, батьківських класів). Кажуть, що спадковість описується відношенням «is-a» і породжує ієрархію «узагальнення-спеціалізація».

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

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

class Student

{char* name, *group;}

Class Starosta: public Student {int level;}

Клас Starosta похідний від класу Student, а Student – базовий для Starosta.

Клас Starosta крім своїх власних членів (level) містить і члени класу Student.

Виведення похідного класу із базового робить його підтипом базового. Тому вказівник на базовий клас можна використовувати як вказівник на похідний (але не навпаки). Наприклад:

void f(Student * p, Starosta *q)

{Student *KA01 [10];

KA01[0] = p;

KA02[1] = q;…}

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

У С++ існує три різновиди успадкування:

  • відкрите (public),

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

  • за замовчуванням закрите (private). У цьому випадку усі відкриті і захищені поля базового класу стали б закритими членами похідного класу. Звернутися до цих полів прямо тепер неможливо — клас так би мовити “закривається”.

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

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

Конструктори похідних класів. У оголошенні будь-якого конструктора похідного класу потрібно враховувати наступне:

  • конструювання об’єкту похідного класу обов’язково відбувається з викликом конструктора базового класу;

  • якщо явний виклик конструктора базового класу не передбачено у конструкторі похідного, за замовчуванням буде викликано конструктор без параметрів базового класу;

  • для організації виклику потрібної версії конструктора базового класу можна скористатися списком ініціалізації, наприклад:

Student :: Student (char*a, char* b): name (a), group (b) {…}

Starosta :: Starosta (char*a, char* b, int c): Student (a,b), level (c) {…}

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

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

5.4. Зразок виконання роботи

Створити базовий клас TwoShape, в якому зберігаються основні параметри (ширина та висота) двовимірного об’єкта, й похідний клас Triangle, створений на основі TwoShape.

#include "stdafx.h"

#include <iostream>

#include <cstring>

#include <conio.h>

using namespace std; // оголошення базового класу

class TwoShape

{

public:

double width;

double height;

void showDim()

{

cout << "Width and height amount to " << width << " and " << height << "\n";

}

};

// оголошення похідного класу

class Triangle : public TwoShape

{

public:

char style[20];

double area()

{

return width* height/2;

}

void showStyle()

{

cout << "This triangle is" << style << "\n";

}

};

int _tmain(int argc, _TCHAR* argv[])

{

Triangle t1;

Triangle t2;

//всі члени класу Triangle доступні для об'єктів класу

//Triangle, навіть ті, що наслідувані від класу TwoShape

t1.width=4.0;

t1.height =4.0;

strcpy(t1.style,"isosceles"); // рівнобедрений

t2.width=8.0;

t2.height =12.0;

strcpy(t2.style,"right"); // прямокутний

cout << "Information about triangle t1:\n";

t1.showStyle();

t1.showDim();

cout<<"Triangle area "<<t1.area()<<"\n"<<"\n";

cout << "Information about triangle t2:\n";

t2.showStyle();

t2.showDim();

cout<<"Triangle area "<<t2.area()<<"\n";

getch();

return 0;

}

В даному прикладі клас TwoShape визначає атрибути „узагальненої” двохвимірної фігури (наприклад, квадрата, прямокутника, трикутника тощо). В класі Triangle створюється специфічний тип об’єкта класу TwoShape, в даному випадку трикутник. Клас Triangle містить всі елементи класу TwoShape й, крім того, поле style, функцію area() та функцію showStyle(). У змінній style зберігається опис типу трикутника, функція area() обчислює й повертає його площу, а функція showStyle() відображає дані про тип трикутника.

Звернімо увагу на синтаксис, що використовується в оголошенні класу Triangle, щоб зробити його похідним від класу TwoShape.

class Triangle : public TwoShape {

Оскільки клас Triangle включає всі члени базового класу TwoShape, то він може звертатися до членів width й height всередині методу area(). Крім того, всередині функції main() об’єкти t1 й t2 можуть безпосередньо посилатися на члени width й height так, немов би вони є частиною класу Triangle.

Рис. 1. Вигляд вікна в результаті компіляції програми

Рис. 2. Діаграма класів

5.5. Індивідуальні завдання

Варіант1. Клас “учасник”: прізвище, телефон, адреса.

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

В похідних класах перевантажити бінарні операції порівняння (“<“ та “!=“) – за датою поставлення на облік і тривалістю доповіді; унарний “-“ - для зміни пункту про наявність пільги і про потребу в поселенні - на протилежне значення.

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

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

В похідних класах перевантажити бінарний мінус А-В як “А б’є В" і операцію [ ] - за порядковим номером – для виведення координат відповідної фігури. Функцію “хід” перетворити на віртуальну.

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

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

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

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

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

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

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

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

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

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

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

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

Варіант 7. Клас “годинник”: стиль відображення (24 чи 12),години, хвилини, секунди. Метод “плюс секунда” – збільшити поточне значення часу на 1 секунду.

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

В похідних класах перевантажити операції “++” – для зсуву зображення на 1 позицію; бінарний “+” – для збільшення зображення об’єкта - результату. Функцію draw перетворити на віртуальну.

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

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

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

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

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

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

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

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

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

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

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

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

Варіант 12. Клас “довге число”: кількість знаків, основа системи числення.

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

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

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

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

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

Варіант 14. Клас “ істота ”: координати, вік, назва. Метод move – збільшення координат на 1.

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

Бінарна операція А-В допустима тільки для об’єктів, які знаходяться поруч (у 8 напрямках) і тільки якщо А – хижак, а В – здобич, або А – здобич, а В - рослина, тоді об’єкт В знищується, а об’єкт А пересувається на одну позицію і його вік збільшується на 1. Функцію move перетворити на віртуальну.

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

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

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

Варіант 16. Клас “давач”: поточне значення, максимально і мінімально допустимі, тип (t, p, i, pH), сигнал тривоги.

Похідні: “круглий дисплей”(x, y, R), “прямокутний дисплей”(координати протилежних кутів), визначити для базового класу масив максимальних значень за добу для кожного типу. Функція view – поточне і максимальне за добу в залежності від типу - для кожного класу з різною реалізацією і функцію set_current_value, яка має змінювати і поточне значення і, в разі необхідності, максимальне за добу.

В обох класах перевантажити бінарну операцію “>” за поточними значеннями, якщо давачи одного типу, і унарну “++” – як R++ і x2++, y2++ відповідно. Функцію view перетворити на віртуальну.

Варіант 17. Клас “товар на складі”: назва, кількість, місце розташування) .

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

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

Варіант 18. Клас “фраза”: (кількість слів, кількість символів, кількість різних символів.

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

В обох класах перевантажити бінарні операції “= =” – порівняння відповідно до семантики, “&“ – порозрядне для війкового запису чисел або як по символьний перетин для речень з врахуванням місця розташування символів. Функцію view перетворити на віртуальну.

Варіант 19. Клас “Число”: кількість цифр, основа системи числення .

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

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

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

  1. Що таке механізм успадкування?

  2. Які переваги використання успадкування?

  3. Опишіть синтаксис використання успадкування.

  4. Чи можуть функції похідного класу використовувати закриті члени базового класу?

  5. Які типи успадкування Ви знаєте?

  6. Який порядок виклику конструкторів та деструкторів при успадкуванні?

  7. Що таке заміщення методу?

  8. Які різновиди ієрархій Ви знаєте?

Лабораторна робота №6. Множинне успадкування

МЕТА РОБОТИ: освоїти механізм множинного успадкування та здобути практичні навики по роботі з його реалізацією.

6.1. Програма роботи

6.1.1. Отримати завдання. Ознайомитись з правилами оголошення та використання віртуальних функцій.

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

6.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

6.1.4. Оформити електронний звіт про роботу та захистити її.

6.2. Вказівки до виконання роботи

6.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 6.5 і записує його до звіту.

6.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 6.4.

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

6.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми, які виведені в вікно форми;

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

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

6.3. Теоретичні відомості

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

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

class BorrowableItem { //

public:

void checkOut();

...

};

class ElectronicGadget {

private:

bool checkOut() const; // виконує самотестування, повертає

... // ознаку успішності тесту

};

class MP3Player: // множинне наслідування (в деяких

public BorrowableItem, // бібліотеках реалізована функціональність,

public ElectronicGadget // необхідна для MP3-плеєрів)

{...} // визначення класу не є важливим

MP3Player mp;

mp.checkout(); // неоднозначнсть! Який саме checkOut?

Варто зазначити, що у цьому випадку виклик функціїї checkout() неоднозначний, нежважаючи на те, що доступна лише одна із функцій (в класі BorrowableItem вона відкрита, а у ElectronicGadget – закрита). Щоб вирішити неоднозначність, необхідно вказати ім’я базового класу, функцію якого необхідно викликати:

mp.BorrowableItem.checkout();

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

Нехай для деяких працівників необхідно вказати їх освіту в програмі Employ. Допустимо. Що у іншій програмі існує клас student, в якому вказується освіта кожного студента. Тоді, замість зміни класу employee ми скоротаємося даними класу student за допомогою множинного наслідування.

У класі student містяться дані про школу чи університет, які закінчив студент, и про рівень отриманої ним освіти. Ці дані зберігаються в рядковому форматі. Методи getedu() та putedu() дозволяють нам ввести дані про студента і переглянути їх.

Інформація про освіту потрібна нам не для всіх працівників. Припустимо, що нам не потрібні записи про освіту для робітників, а потрібні тільки для менеджерів та науковців. Тому ми модифікуємо класи manager і scientist таким чином, що вони будуть похідними класів employee та student, як це зображено на рис.1.

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

Class student

{ };

class employee

{ };

class manger: public employee, private student

{ };

class scientist: private employee, private student

{ };

class laborer: public employee

{ };

Рис.1. Діаграма класів

6.4. Зразок виконання роботи

Згідно завдання, поданого у теоретичних відомостях розроблено наступну програму:

#include "stdafx.h"

#include <iostream>

using namespace std;

const int LEN=80;

class student

{

private:

char school[LEN];

char degree[LEN];

public:

void getedu()

{

cout<<"Vveditj nazvy navchaljnogo zaklady\t";

cin>>school;

cout<<"Vveditj stepinj osvitu\t";

cout<<"nepovna vushcha, bakalavr, magistr, kand.nauk\t";

cin>>degree;

}

void putedu () const

{

cout<<"\nNavchaljnuj zaklad\t"<<school;

cout<<"\nStepinj\t"<<degree;

}

};

class employee

{

private:

char name[LEN];//прізвище

unsigned long number;//Номер

public:

void getdata()

{

cout<<"Vveditj prizvushche\t";

cin>>name;

cout<<"Vveditj nomer\t";

cin>>number;

}

void putdata () const

{

cout<<"\nPrizvushche\t"<<name;

cout<<"\nNomer\t"<<number;

}

};

class manager:private employee, private student//Менеджер

{

private:

char title[LEN];//посада співробітника

double dues;//сума премій

public:

void getdata()

{

employee::getdata();

cout<<"Vveditj posadu\t";

cin>>title;

cout<<"Vveditj symu premij\t";

cin>>dues;

student::getedu();

}

void putdata () const

{

employee::putdata();

cout<<"\nPosada\t"<<title;

cout<<"\nSuma premij\t"<<dues;

student::putedu();

}

};

class scientist: private employee, private student//Науковець

{

private:

int pub;//кількість публікацій

public:

void getdata()

{

employee::getdata();

cout<<"Vveditj k-istj publikacij\t";

cin>>pub;

student::getedu();

}

void putdata() const

{

employee::putdata();

cout<<"\nK-istj publikacij\t"<<pub;

student::putedu();

}

};

class laborer:public employee//Робітник

{

};

int _tmain(int argc, _TCHAR* argv[])

{

manager m1;

scientist s1;

laborer l1;

cout<<"\n";

cout<<"---Meneger---\n";

m1.getdata();

cout<<"---Naykovecj---\n";

s1.getdata();

cout<<"---Robitnuk---\n";

l1.getdata();

cout<<"\n\n";

cout<<"---informacija pro menegera---";

m1.putdata();

cout<<"\n\n";

cout<<"---informacija pro naykovcja---";

s1.putdata();

cout<<"\n\n";

cout<<"---informacija pro robitnuka---";

l1.putdata();

int q;

cin>>q;

return 0;

}

Функції getdata() і putdata() класів manager та scientist містять у собі такі виклики функцій класу student як student::getedu();student::putedu();

Ці методи доступні вищезазначеним класам, оскільки названі класи успадковуються від класу student.

Результати роботи програми:

Діаграма класів програмного коду:

6.5. Індивідуальні завдання

До структури розроблених класів, розроблених у ЛР№5 додати ще 1 клас для забезпечення множинного успадкування.

Варіант1.

А). Клас “учасник”: прізвище, телефон, адреса.

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 2.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 3.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 4.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 5.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 6.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 7.

А). Клас “годинник”: стиль відображення (24 чи 12),години, хвилини, секунди. Метод “плюс секунда” – збільшити поточне значення часу на 1 секунду.

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 8.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 9.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 10.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 11.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 12.

А). Клас “довге число”: кількість знаків, основа системи числення.

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 13.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 14.

А). Клас “ істота ”: координати, вік, назва. Метод move – збільшення координат на 1.

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 15.

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

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 16.

А). Клас “давач”: поточне значення, максимально і мінімально допустимі, тип (t, p, i, pH), сигнал тривоги.

Похідні: “круглий дисплей”(x, y, R), “прямокутний дисплей”(координати протилежних кутів), визначити для базового класу масив максимальних значень за добу для кожного типу. Функція view – поточне і максимальне за добу в залежності від типу - для кожного класу з різною реалізацією і функцію set_current_value, яка має змінювати і поточне значення і, в разі необхідності, максимальне за добу.

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 17.

А). Клас “товар на складі”: назва, кількість, місце розташування) .

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 18.

А). Клас “фраза”: (кількість слів, кількість символів, кількість різних символів.

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами

Варіант 19.

Клас “Число”: кількість цифр, основа системи числення .

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

Б). Згідно зображеної структури описати класи на мові С++ та наповнити методами.

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

1. Що таке невизначеність при успадкуванні?

2. Наведіть приклад множинного успадкування?

3. Наведіть синстаксис множинного успадкування для мови С++.

4. Який за замовчуванням модифікатор доступ використовується при успадкуванні?

5. Як можна уникнути невизначеності?

6. Чи є обмеження у кількості рівнів у ієрархії успадкування? Чому?

7 . Охарактеризуйте модифікатори доступу при успадкування.

Лабораторна робота №7. Поліморфізм та віртуальні функції

МЕТА РОБОТИ: освоїти механізм пізнього зв’язування через використання віртуальних функції при простому й множинному успадкуванні в класах.

7.1. Програма роботи

7.1.1. Отримати завдання. Ознайомитись з правилами оголошення та використання віртуальних функцій.

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

7.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

6.1.4. Оформити електронний звіт про роботу та захистити її.

7.2. Вказівки до виконання роботи

7.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 7.5 і записує його до звіту.

7.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 7.4.

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

7.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми, які виведені в вікно форми;

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

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

7.3. Теоретичні відомості

Під час обговорення об'єктно-орієнтованих мов програмування зазвичай використовують два терміни: раннє зв'язування (early binding) і пізнє зв'язування (late binding). При ранньому зв'язуванні виклик функції готується під час компілювання, а при пізньому – у процесі виконання програми. Пізнє зв'язування у мові програмування C++ досягається за рахунок використання віртуальних функцій і похідних типів. Перевага пізнього зв'язування полягає у тому, що воно забезпечує великий ступінь гнучкості. Його можна застосовувати для підтримки загального інтерфейсу і давати змогу при цьому різним об'єктам, які використовують цей інтерфейс, визначати їх власні реалізації.

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

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

Для віртуальних функцій є такі правила:

− віртуальну функцію неможна обявляти як static;

– функціям деструкторів дозволено бути віртуальними, а функціям конструкторів – ні;

− специфікатор virtual необовязковий при перевизначенні функції в похідному класі;

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

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

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

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm) { x = izm; y = jzm;}

virtual void showArea() {

cout << "У цьому класі виразу для обчислення "

<< "площі не визначено.\n";}

};

class triAngle : public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

<< " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle : public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

  • << " має площу " << х * y << ".\n";}

};

int main()

{

figUre *p; // Створення покажчика на об'єкт базового типу

triAngle T_ob; // Створення об'єктів похідних типів

rectAngle R_ob; // Створення об'єкта похідного типу

p = &T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

cout<<"Натиснiть будь-яку клавiшу!";

while(!kbhit());

}

Ось як виглядають результати виконання цієї програми:

Трикутник з висотою 10 і основою 5 має площу 25.

Прямокутник розмірами 10 х 5 має площу 50.

У цій програмі під час роботи з класами rectAngle і triAngle використано однаковий інтерфейс, хоча у них реалізовані власні методи обчислення площі відповідних об'єктів.

Як ми уже зазначали вище, якщо віртуальна функція, яка не перевизначена у похідному класі, викликається об'єктом цього похідного класу, то використовується та її версія, що була визначена в базовому класі. Але у багатьох випадках взагалі немає сенсу давати визначення віртуальної функції в базовому класі. Суто віртуальна функція – це віртуальна функція, яка не має визначення в базовому класі. Тому будь-який похідний тип повинен визначити власну версію цієї функції, адже у нього просто немає ніякої можливості використовувати версію з базового класу (через її відсутність). Щоб оголосити суто віртуальну функцію, використовують такий загальний формат:

virtual тип ім'я_функції (список_параметрів) = 0;

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

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm) { x = izm; y = jzm;}

virtual void showArea() = 0; // Суто віртуальна функція

};

class triAngle : public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

  • << " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle : public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

  • << " має площу " << х * y << ".\n";}

};

class cirCle : public figUre {

// Відсутність визначення функції showArea()

// Викличе повідомлення про помилку.

};

int main()

{

figUre *p; // Створення покажчика на об'єкт базового типу

triAngle T_ob; // Створення об'єкта похідного типу

rectAngle R_ob; // Створення об'єкта похідного типу

cirCle С_ob; // Помилка: створення цього об'єкта є неможливим!

p = & T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

cout<<"Натиснiть будь-яку клавiшу!";

while(!kbhit());

}

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

7.4. Зразок виконання роботи

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

Employee.h

#pragma once

#include <iostream>

using namespace std;

class Employee{

protected:

char * firstName, * lastName; // Ім’я, прізвище.

int age; // Вік.

double payRate; // Розмір оплати.

public:

Employee (char* FN, char* LN, int a, double pay);

virtual double CalculatePay (){return 0;};

void print();

virtual ~Employee (){};

};

Employee.cpp

#include "StdAfx.h"

#include "Employee.h"

#include < iostream>

#include < fstream>

#include < conio.h>

#include < string.h>

Employee::Employee (char* FN, char* LN, int a, double pay){

firstName = new char [strlen (FN) + 1];

strcpy(firstName, FN);

lastName = new char [strlen (LN) + 1];

strcpy(lastName, LN);

age = a;

payRate = pay;

}

void Employee::print(){

setlocale( LC_ALL,"Ukrainian" );

cout<<firstName;

cout.width (8);

cout<<lastName;

cout.width (25);

cout<<"цього мiсяця отримав";

cout.width (8);

}

ContractorEmployee.h

#pragma once

#include "employee.h"

class ContractorEmployee: public Employee { // Робота за контрактом.

public:

ContractorEmployee (char* FN, char* LN, int a, double pay): Employee (FN, LN, a, pay){}

virtual double CalculatePay (){ return payRate; }

virtual ~ContractorEmployee (){delete firstName; delete firstName;}

};

DaypaymentEmployee.h

#pragma once

#include "employee.h"

class DaypaymentEmployee: public Employee { // Поденна оплата.

int days; // Відпрацьовано днів.

public:

DaypaymentEmployee (char* FN, char* LN, int a, double pay, int d):

Employee (FN, LN, a, pay){days=d;}

virtual double CalculatePay (){ return days*payRate/24.0; // Робочих днів в місяці - 24.

}

virtual ~DaypaymentEmployee (){delete firstName; delete firstName;}

};

HourlyEmployee.h

#pragma once

#include "employee.h"

class HourlyEmployee: public Employee { // Погодинна оплата.

int hours; // Відпрацьовано годин.

public:

HourlyEmployee (char* FN, char* LN, int a, double pay, int h): Employee (FN, LN, a, pay){ hours=h; }

virtual ~HourlyEmployee (){delete firstName; delete firstName;}

virtual double CalculatePay (){ return hours*payRate; }

};

Lab6.cpp

#include "stdafx.h"

#include "Employee.h"

#include < iostream>

#include < fstream>

#include < conio.h>

#include < string.h>

#include "ContractorEmployee.h"

#include "DaypaymentEmployee.h"

#include "HourlyEmployee.h"

using namespace std;

void loademploee (Employee* a[], int &n){

char FN[20], LN[20]; int age, arg; double pay;

char sel; // Селектор, що задає тип оплати

ifstream file ( "emp.dat" ); // Створюємо вхідний потік для читання

// file і звязуємо його з зовнішнім файлом emp.dat.

n = 0;

while ( file.peek ( ) != EOF ){ // Поки немає кінця файлу …

file >> sel;

file >> FN;

file >> LN;

file >> age;

file >> pay;

file >> arg;

switch (sel){

case 'h': a[n] = new HourlyEmployee (FN, LN, age, pay, arg);

break;

case 'c': a[n] = new ContractorEmployee (FN, LN, age, pay);

break;

case 'd': a[n] = new DaypaymentEmployee (FN, LN, age, pay, arg);

break;

}

n++;

}

}

void main(){

setlocale( LC_ALL,"Ukrainian" );

int n=3;

Employee* a[3];

//clrscr();

loademploee (a, n);

double s=0, r;

for(int i=0; i<=3; i=i+1)

{r=a[i]->CalculatePay ();

s+=r;

a[i]->print();

cout << r << "$\n";}

cout<<"За цей мiсяць заплачено: ";

cout <<s << "$\n";

cout<<"Натиснiть будь-яку клавiшу!";

while(!kbhit());

}

Рис. 1. Вигляд вікна в результаті компіляції програми

Рис. 2. Вміст файлу emp.dat

Рис. 3. Діаграма класів

7.5. Індивідуальні завдання

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

2. Створити абстрактний базовий клас з віртуальною функцією: норма. Створити похідні класи: комплексні числа, вектор з 10 елементів, матриця (2×2). Визначити функцію норми: для комплексних чисел – модуль числа, для вектора – корінь квадратний з суми квадратів елементів, для матриці – максимальне значення за модулем. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси різних об’єктів.

3. Створити абстрактний клас криві для обчислення залежностей y від x. Створити похідні класи: пряма, еліпс, гіпербола з своїми функціями обчислення y(x) залежно від вхідного параметра х (рівняння прямої – у=ах+b, еліпса – x2/a2+y2/b2=1, гіперболи – x2/a2-y2/b2=1). Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси різних об’єктів.

4. Створити абстрактний базовий клас з віртуальною функцією – сума прогресії. Створити похідні класи: арифметична прогресія і геометрична прогресія. Кожен клас має два поля типу double. Перше – перший член прогресії, друге – постійна різниця для арифметичної і постійне відношення – для геометричної прогресії. Визначити функцію обчислення суми, де параметром є кількість елементів прогресії (арифметична прогресія: aj=a0+jd, j=0,1,2,… і її сума sn=(n+1)(a0+an)/2, геометрична прогресія: aj=a0rj, j=0,1,2,… і її сума sn=( a0-anr)(1-r). Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси різних об’єктів.

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

6. Створити абстрактний базовий клас з віртуальною функцією – площа поверхні. Створити похідні класи: пералелепіпед, тетраедр, куля з своїми функціями площі поверхні. Площа поверхні паралелепіпеда – 6xy, кулі – 4πr2, тетраедра – a2*31/2. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси різних об’єктів.

7. Створити абстрактний базовий клас з віртуальною функцією – об’єм. Створити похідні класи: пералелепіпед, піраміда, тетраедр, куля з своїми функціями об’єму. Об’єм паралелепіпеда – xyz, піраміди – xyh, кулі – 4πr3/3, тетраедра – a3*21/2/12. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси різних об’єктів.

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

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

10. Створити абстрактний базовий клас з віртуальною функцією – корені рівняння. Створити похідні класи: клас лінійних рівнянь і клас квадратних рівнянь. Визначити функцію обчислення коренів рівнянь. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси різних об’єктів.

11. Створити абстрактний базовий клас для роботи з геометричними фігурами на екрані. У захищеній частині класу знаходяться такі дані: координати центра фігури, кут повороту в градусах, масштабний фактор. У відкритій частині розміщено функції-методи: зобразити фігуру на екрані, приховати фігуру (знищити зображення), повернути фігуру на заданий кут, перемістити фігуру на заданий вектор. Застосовуючи успадкування та наведений вище абстрактний клас, створити похідні класи для роботи з фігурою типу трикутник, чотирикутник, багатокутник. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси об’єктів похідних класів.

12. Створити абстрактний базовий клас для роботи з геометричними фігурами на екрані. У захищеній частині класу знаходяться такі дані: координати центра фігури, кут повороту в градусах, масштабний фактор. У відкритій частині розміщено функції-методи: зобразити фігуру на екрані, приховати фігуру (знищити зображення), повернути фігуру на заданий кут, перемістити фігуру на заданий вектор. Застосовуючи успадкування та наведений вище абстрактний клас, створити похідні класи для роботи з фігурою типу коло і еліпс. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси об’єктів похідних класів.

13. Створити абстрактний базовий клас для виведення графіків функцій. У захищеній частині класу знаходяться такі дані: координати початку системи координат, кути повороту осей в градусах, масштабний фактор. У відкритій частині розміщено функції-методи: зобразити графік на екрані, приховати графік (знищити зображення), повернути осі координат на задані кути, перемістити графік на заданий вектор. Застосовуючи успадкування та наведений вище абстрактний клас, створити похідні класи для виведення графіків у Декартові та полярній системах координат. Для перевірки визначити масив вказівників на абстрактний клас, яким присвоюються адреси об’єктів похідних класів.

14. У відкритій частині базового класу знаходиться віртуальний метод, який виводить назву свого класу. Утворити два похідні класи DerA i DerB. Від класів DerA i DerB шляхом множинного успадкування створити клас DerAB. Перевизначити в кожному з класів віртуальну функцію так, щоб вона виводила на екран дійсне ім’я класу об’єкту, з якого вона викликається. Для кожного з класів створеної ієрархії створити по одному об’єкту і для кожного з них викликати віртуальну функцію. Створити масив із N вказівників на базовий клас ієрархії. Для кожного з них створити динамічний об’єкт, по одному для кожного з класів ієрархії. Викликати віртуальні функції для кожного з динамічних об’єктів за допомогою вказівників.

15. Написати програму з використанням віртуальних методів, яка оголошує клас Point, що визначає координати пікселя на екрані дисплею та віртуальний метод MoveTo його випадкового переміщення по екрану. Визначити похідний клас Circle, який успадковує клас Point, визначає радіус коло та пере визначає віртуальний метод MoveTo для випадкового переміщення кола в межах екрану.

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

  1. Чи проявляється поліморфізм при перезавантаженні операторів і функцій?

  2. Чи наслідується конструктор у похідному класі?

  3. Для чого використовуються віртуальні функції?

  4. Чи можуть функції похідного класу використовувати закриті члени базового класу?

  5. Чи можливе повторне визначення віртуальних функцій у похідному класі?

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

  7. Які властивості мають дружні функції та дружні класи?

  8. Що таке поліморфізм в ООП?

  9. Чи може виклик однієї і тієї ж функції з однаковими параметрами при використанні принципів ООП дати різні результати?

  10. В якому випадку множинного наслідування базовий клас та його функції описуються віртуальними?

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

  12. Поясніть суть правила домінування імен при множинному наслідуванні.

Лабораторна робота №8. Шаблони функцій і класів

МЕТА РОБОТИ: навчитись створювати та використовувати шаблони функцій та узагальнені класи.

8.1. Програма роботи

8.1.1. Отримати завдання.

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

8.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

8.1.4. Оформити електронний звіт про роботу та захистити її.

8.2. Вказівки до виконання роботи

8.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 8.5 і записує його до звіту.

8.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 8.4.

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

8.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

8.3. Теоретичні відомості

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

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

Узагальнена функція – це функція, яка перевантажує сама себе.

template <class Ttype> тип ім'я_функції (список_параметрів)

{

// тіло функції

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

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

Загальний формат оголошення узагальненого класу має такий вигляд:

template <class Ttype> class ім'я_класу {

.

.

.

}

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

Створивши узагальнений клас, можна створити його конкретний примірник, використовуючи такий загальний формат:

ім'я_класу <тип> ім'я_об'єкту;

У цьому записі елемент тип означає ім'я типу даних, які оброблятимуться примірником узагальненого класу. Функції-члени узагальненого класу автоматично є узагальненими. Тому програмісту не потрібно використовувати ключове слово template для безпосереднього визначення їх такими.

8.4. Зразок виконання роботи

Завдання 1. Створити шаблон функції для визначення абсолютного значення числа і продемонструвати її роботу для різних типів: int, double, float, long.

#include "stdafx.h"

#include <iostream>

#include <string>

#include <ctime>

#include <conio.h>

using namespace std; // Використання стандартного простору імен

template <class aType> aType myAbs(aType num)

{

return num < 0 ? -num : num;

}

int main()

{

cout << myAbs(-10) << "\n"; // Для типу int

cout << myAbs(-10.0) << "\n"; // Для типу double

cout << myAbs(-10L) << "\n"; // Для типу long

cout << myAbs(-10.0F) << "\n"; // Для типу float

cout<<"press any key!";

while(!kbhit());

}

Рис.1. Вигляд вікна виконавчого файлу, діаграма класів та діаграма варіантів використання завдання 1

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

#include "stdafx.h"

#include <iostream>

#include <ctype.h>

#include <string>

#include <conio.h>

#include <stdlib.h>

using namespace std;

template<class T, class T1> class array1

{

private:

T *data;

int size;

int index;

public:

array1(int size);

T1 sum(void);

T average_value(void);

void show_array1(void);

int add_value(T);

};

template<class T, class T1> array1<T, T1>::array1(int size)

{ setlocale( LC_ALL,"Ukrainian" );

data = new T[size];

if (data == NULL)

{ cerr << "Недостатньо пам'ятi - програма завершується";cout << endl;

exit(1);

}

array1::size = size;

array1::index = 0;

}

template<class T, class T1> T1 array1<T, T1>:: sum(void)

{ T1 sum = 0;

for (int i = 0; i < index; i++) sum += data[i];

return(sum);

}

template<class T, class T1> T array1<T, T1>::average_value(void)

{ T1 sum =0;

for (int i = 0; i < index; i++) sum += data[i];

return (sum / index);

}

template<class T, class T1> void array1<T, T1>::show_array1(void)

{ for (int i = 0; i < index; i++) cout << data[i] << ' ';

cout << endl;

}

template<class T, class T1> int array1<T, T1>::add_value(T value)

{ if (index == size)

return(-1); // Масив повен

else

{

data[index] = value;

index++;

return(0); // Успiшно

}

}

void main(void)

{

setlocale( LC_ALL,"Ukrainian" );

// Масив з 100 елементiв

array1<int, long> numbers(100);

// Масив з 200 елементiв

array1<float, float> values(200);

int i;

for (i = 0; i < 50; i++) numbers.add_value(i);

numbers.show_array1();

cout << "Сума чисел рiвна ";cout << numbers.sum () << endl;

cout << "Середнє значення рiвне ";cout << numbers.average_value() << endl;

for (i = 0; i < 100; i++) values.add_value(i * 100);

values.show_array1();

cout <<"Сума чисел рiвна "; cout<< values.sum() << endl;

cout << "Середнє значення рiвне ";cout<< values.average_value() << endl;

while(!kbhit());

}

Рис.2. Вигляд вікна виконавчого файлу, діаграма класів та діаграма варіантів використання завдання 2

8.5. Індивідуальні завдання

Завдання 1

  1. Створити шаблонну функцію для сортування елементів за методом бульбашки. Продемонструвати її роботу для даних типу int i char.

  2. Створити шаблонну функцію для сортування елементів за методом перестановок. Продемонструвати її роботу для даних типу int i char.

  3. Створити шаблону функцію для сортування елементів вибіркою. Продемонструвати її роботу для даних типу int i char.

  4. Створити шаблонну функцію для знаходження елементу в неупорядкованому масиві. Продемонструвати її роботу для двох типів даних.

  5. Створити шаблонну функцію для знаходження елементу в впорядкованому масиві. Продемонструвати її роботу для двох типів даних.

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

  7. Створити шаблону функцію для інверсії елементів масиву. Продемонструвати її роботу для двох типів даних.

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

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

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

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

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

  13. Створити шаблонну функцію для заміни елементів масиву на їх значення піднесені до квадрату. Продемонструвати її роботу для двох типів даних.

  14. Створити шаблонну функцію для підрахунку кількості цифр в числі. Продемонструвати її роботу для двох типів даних.

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

Завдання 2

  1. Створити шаблонний клас vector з двома параметрами: перший є параметром типу, а другий – цілочисельним значенням. Визначити конструктор, деструктор, методи пошуку екстремуму, впорядкування, обчислення евклідової норми. Перевантажити операції +, =, [], <<, >> відповідно для додавання, присвоєння, контролю діапазону індексу, виведення та введення об’єктів.

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

  3. Створити шаблонний клас для визначення норми елемента заданого типу. Для комплексних чисел норма визначається як модуль комплексного,для вектора – як корінь квадратний із суми квадратів елементів, для матриці – максимальне значення за модулем. Застосувати клас для пошуку елементів різних типів.

  4. Створити параметризований масив з конструкторами, деструктором і перезавантаженими операціями [], =, виведення у потік << та введення з потоку >>.

  5. Створити шаблонний клас для сортування одновимірного масиву за зростанням значень елементів. Застосувати цей клас для сортування масивів цілих та дійсних чисел, масивів символів та рядків символів.

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

  7. Створити параметризований шаблонний клас – множина, який призначений для збереження елементів і виконання операцій над ними. Реалізувати класичні операції над множинами – об’єднання, перетину, різниці, порівняння та операції введення та виведення.

  8. Створити клас – стек, що базується на статичному масиві покажчиків. Тип елементів стеку визначається параметром шаблону. Передбачити функції для виконання таких операцій: занесення елемента у стек; вилучення значення із вершини стеку; виведення усіх значень стеку на екран; повернення кількості елементів стеку.

  9. Створити клас – стек, що базується на структурі зв’язаного списку динамічної пам’яті. Тип елементів стеку визначається параметром шаблону. Передбачити функції для виконання таких операцій: занесення елемента у стек; вилучення значення із вершини стеку; виведення усіх значень стеку на екран; повернення кількості елементів стеку.

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

  11. Створити параметризований клас бінарного дерева з методами – додати елемент до дерева проходження по дереву в спадному і висхідному порядку. Здійснити пошук за деревом.

  12. Написати шаблонний клас, який знаходить контрольну суму елемента довільного типу. Контрольна сума – це кількість одиниць у машинному зображенні заданого елемента.

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

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

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

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

  1. Яка функція називається шаблонною (узагальнюючою)?

  2. З якого ключового слова визначення оголошення шаблонної функції?

  3. Що таке спеціалізація чи конкретизація шаблонної функції?

  4. Що таке породжена функція?

  5. Скільки типів можна визначити в шаблонній функції і від чого це залежить?

  6. Що таке безпосередня спеціалізація?

  7. Чи можна перезавантажувати шаблонну функцію і якщо можна то як?

  8. Як у шаблонних функціях використовують поряд із узагальненими стандартні параметри? Приклад.

  9. Які обмеження є на застосування шаблонних функцій?

  10. Як записати конкретний примірник узагальненого класу? Приклад.

  11. Чи є функції-члени узагальненого класу узагальненими і як записують їх визначення? Приклад.

  12. В яких випадках доцільно створювати узагальнені класи?

  13. Чи можна створювати узагальнені класи з декількома узагальненими типами даних і як це зробити, якщо можна? Приклад.

  14. Які обмеження накладаються при використанні аргументу в узагальнених класах, який не є типом?

  15. Як визначити в шаблонних класах аргумент за замовчуванням для узагальненого типу? Приклад.

  16. Як визначити в шаблонних класах аргумент за замовчуванням для неузагальненого типу? Приклад.

  17. Що таке спеціалізація класу? Приклад.

Лабораторна робота №9. засоби ОПРА ЦЮВАННЯ ВИняткових СИТУАЦІЙ В C++

МЕТА РОБОТИ: навчитись перехоплювати і обробляти різного роду виняткові ситуації, які виникають в процесі розроблення програм з використанням об’єктно-орієнтованого підходу.

9.1. Програма роботи

9.1.1. Отримати завдання.

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

9.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

9.1.4. Оформити електронний звіт про роботу та захистити її.

9.2. Вказівки до виконання роботи

9.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 9.5 і записує його до звіту.

9.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 9.4.

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

9.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

9.3. Теоретичні відомості

Оброблення винятків – це системні засоби, за допомогою яких програма може справитися з помилками часу виконання.

Керування С++-механізмом оброблення винятків тримається на трьох ключових словах: try, catch і throw. Програмні настанови, які Ви вважаєте за потрібне проконтролювати на предмет винятків, поміщаються в try-блок. Якщо виняток (тобто помилка) таки виникає у цьому блоці, то він дає знати про себе шляхом викидання певного роду інформації (за допомогою ключового слова throw). Цей викинутий виняток можна перехопити програмним шляхом за допомогою catch-блоку і оброблений відповідним чином.

Загальний формат try- і catch-блоків має такий вигляд:

try {

// try-блок (блок коду програми, що підлягає перевірці

// на наявність помилок)

}

catch(aType arg) {

// catch-блок (обробник винятків типу aType)

}

catch(bType arg) {

// catch-блок (обробник винятків типу bType)

}

catch(cType arg) {

// catch-блок (обробник винятків типу cType)

}

//....

catch(nType arg) {

// catch-блок (обробник винятків типу nType)

}

Блок try повинен містити програмний код, який, на Вашу думку, повинен перевірятися на предмет виникнення помилок. Цей блок може містити тільки декілька настанов деякої функції або охоплювати весь код функції main(). Виконується та catch-настанова, тип винятку якої (тобто тип даних, що задається в catch-настанові) збігається з типом згенерованого винятку (а всі інші будуть проігноровані). Після перехоплення винятку параметр arg прийме його значення. Таким шляхом можуть перехоплюватися дані будь-якого типу, в т.ч. об'єкти класів, що були створені програмістом.

Щоб виняток було перехоплено, необхідно забезпечити його "викид" в try-блоці.

Загальний формат настанови throw має такий вигляд:

throw exception;

У цьому записі за допомогою елемента exception задається виняток, що згенерується настановою throw. Якщо цей виняток підлягає перехопленню, то настанова throw повинна бути виконана або в самому блоці try, або в будь-якій функції, які викликається з нього (тобто прямо або опосередковано).

int main()

{

cout << "Початок.\n";

try { // Початок try-блоку

cout << "B try-блоці\n";

throw 99; // Генерування помилки

cout << "Ця настанова не буде виконана.";

}

catch(int izm) { // Перехоплення помилки

  • cout << "Значення перехопленого винятку дорівнює: "

<< izm << "\n";

}

cout << "Кінець програми";

return 0;

}

Розглянемо уважно код цієї програми. Як бачите, тут try-блок містить три настанови, а настанова catch(int izm) призначена для оброблення винятку цілочисельного типу. У цьому try-блоці виконуються тільки дві з трьох настанов: cout і throw. Після генерування винятку керування передається catch-виразу, при цьому виконання try-блоку припиняється. Необхідно розуміти, що catch-настанова не викликається, а просто з неї продовжується виконання програми після "викиду" винятку. У загальному випадку try-блок відновлює своє функціонування під час кожного входу в нього.

Функції exit() і abort() забезпечують завершення роботи програми. Для використання функції цих функцій потрібно залучити до програми заголовок <cstdlib>. Виклик функції exit() негайно приводить до "правильного" припинення роботи програми2. Зазвичай цей спосіб завершення роботи використовують для зупинки програми під час виникнення непоправної помилки, яка робить подальше її виконання безглуздим або небезпечним. Її прототип має такий вигляд: void exit(int status);

Функція abort() викликає негайне завершення роботи програми, проте вона не повертає операційній системі ніякої інформації про статус завершення роботи програми і не виконує стандартної ("правильної") послідовності дій під час зупинки програми. Її прототип має такий вигляд: void abort();

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

class myException {

public:

char strMas[80];

myException() { *strMas = 0;}

myException(char *s) { strcpy(strMas, s);}

};

int main()

{

int a, b;

try {

  • cout << "Введіть чисельник і знаменник: ";

  • cin >> а >> b;

  • if(!b) throw myException("Ділити на нуль не можна!");

  • else cout << "Частка дорівнює " << a/b << "\n";

}

catch(myException e) { // Перехоплення помилки

  • cout << e.strMas << "\n";

}

return 0;

}

Перехоплення винятків базового класу. Catch-вираз для базового класу "відреагує збігом" на винятки будь-якого похідного типу (тобто типу, виведеного з цього базового класу). Отже, якщо потрібно перехоплювати винятки як базового, так і похідного типів, то у catch-послідовності catch-настанову для похідного типу необхідно помістити перед catch-настановою для базового типу. Інакше catch-вираз для базового класу перехоплюватиме (крім "своїх") і винятки всіх похідних класів. Розглянемо, наприклад, наведену нижче програму

class bClass { // Оголошення класового типу};

class dClass: public bClass { // Оголошення класового типу};

int main()

{

dClass derived;

try { throw derived; }

catch(bClass b_ob)

  • {cout << "Перехоплення винятку базового класу.\n";}

catch(dClass d_ob)

  • {cout << "Це перехоплення не відбудеться.\n";}

return 0;

}

Оскільки тут об'єкт derived – це об'єкт класу dClass, який виведений з базового класу bClass, то виняток типу derived завжди перехоплюватиметься першим catch-виразом; друга ж catch-настанова при цьому ніколи не виконається. Одні компілятори відреагують на такий стан речей застережливим повідомленням, інші можуть видати повідомлення про помилку. У будь-якому випадку, щоб виправити ситуацію, достатньо поміняти порядок слідування цих catch-настанов на протилежний.

Для перехоплення всіх винятків достатньо використовувати такий формат catch-блоку:

catch(...) {

// Оброблення всіх винятків

}

Повторне генерування винятку. Для цього необхідно скористайтися throw-настановою без вказання типу винятки. У цьому випадку поточний виняток буде передано в зовнішню try/catch-послідовність. Найчастіше причиною для такого виконання настанови throw слугує прагнення дати змогу доступ до одного винятку декільком обробникам. Наприклад, перший обробник винятків повідомлятиме про один аспект винятку, а другий – про інше. Винятки можна повторно згенерувати тільки в catch-блоці (або в будь-якій функції, які викликається з цього блоку). При повторному генеруванні виняток не перехоплюватиметься тією ж catch-настановою. Воно розповсюдиться на найближчу try/catch-послідовність.

void Xhandler() {

try {

  • throw "Привіт"; // Генерує винятки типу char *

}

catch(char *) { // Перехоплює винятки типу char *

  • cout << "Перехоплення винятку у функції Xhandler.\n";

  • throw; // Повторне генерування винятку типу char *,

  • // яке буде перехоплене поза функцією Xhandler.

}

}

int main()

{

cout << "Початок.\n";

try {

  • Xhandler();

}

catch(char *) {

  • cout << "Перехоплення винятку у функції main().\n";

}

cout << "Кінець програми";

return 0;

}

Оброблення винятків, пов’язаних з динамічним виділенням пам’яті. У випадку неможливості задовольнити запит на виділення пам'яті, потрібної оператором new, генерується виняток типу bad_alloc. Якщо Ваша програма не перехопить його, то вона буде достроково завершена. Щоб отримати доступ до винятку типу bad_alloc, потрібно залучити до програми заголовок <new>.

int main()

{

int *p, i;

try {

  • p = new int[32]; // Запит на виділення пам'яті

// для 32-елементного int-масиву

}

catch(bad_alloc ха) {

  • cout << "Пам'ять не виділена.\n";

  • return 1;

}

for(i=0; i<32; i++) p[i] = i;

for(i=0; i<32; i++) cout << p[i] << " ";

delete [] p; // Звільнення пам'яті

return 0;

}

Під час невдалого виконанні оператора new виняток у цій програмі буде перехоплено catch-настановою. Стандарт мови C++ при невдалій спробі виділення пам'яті замість генерування винятку також дає змогу оператору new повертати значення NULL, для цього використовують такий формат оператора new(nothrow) Приклад:

int main()

{

int *p, i;

p = new(nothrow) int[32]; // Використання nothrow-версії

if(!p) {

  • cout << "Пам'ять не виділена.\n";

  • return 1;

}

for(i=0; i<32; i++) p[i] = i;

for(i=0; i<32; i++) cout << p[i] << " ";

delete [] p; // Звільнення пам'яті

return 0;

}

9.4. Зразок виконання роботи

Завдання. Клас В с похідним від класу А. Визначити обробник виняткової ситуації при спробі перетворення об'єкта базового класу А в об'єкт похідного класу В.

Файл A.h

#pragma once

class A

{

protected:int x;

public:

A(int x=0){this->x=x;}

};

Файл B.h

#pragma once

#include "a.h"

class B: public A

{

int y;

public:

B(int x=0,int y=0):A(x){this->y=y;}

B(A a ) {throw a;}

};

Файл A.ccp

#include "StdAfx.h"

#include "A.h"

Файл B.ccp

#include "StdAfx.h"

#include "B.h"

Файл з функцією main

#include <stdio.h>

#include "stdafx.h"

#include "A.h"

#include "B.h"

#include <iostream>

#include <process.h>

using namespace std;

void main( )

{

A a(1);

B b(2,3);

try

{

b=B(a);

cout<<"Continue"<<endl;

}

catch (B)

{

cout<<"catch( B)"<<endl;

exit(1);

}

catch(A)

{

cout<<"catch(A)"<<endl;

exit(2);

}

cout<<"End"<<endl;

}

Рис. 1. Діаграма класів та вигляд вікна в результаті компіляції програми

9.5. Індивідуальні завдання

  1. Неабстрактний клас В є похідним від абстрактного класу А. Визначити обробник виняткової ситуації при перетворенні покажчика на клас В до покажчика на абстрактний клас.

  2. Клас В є похідним від класу А. Визначити обробник виняткової ситуації на перетворення покажчика базового класу А на покажчик похідного класу В.

  3. Клас В є похідним від класу А. Визначити обробник виняткової ситуації на присвоєння об’єкту базового класу А об’єкта похідного класу В.

  4. Клас В є похідним від класу А. Визначити обробник виняткової ситуації при отриманні через список параметрів одним із методів класу В копії об’єкта класу А.

  5. Клас В є похідним від класу А. Визначити обробник виняткової ситуації на само присвоєння об’єктів одного класу.

  6. Клас В є похідним від класу А. Визначити обробник виняткової ситуації при створенні одним із методів класу В об’єкта класу А.

  7. Неабстрактний клас В є похідним від абстрактного класу А. Визначити обробник виняткової ситуації при перетворенні посилання на клас В у посилання на абстрактний клас.

  8. Клас В є похідним від класу А. У класі В оголошено метод, який повертає об’єкт цього самого класу. Визначити обробник виняткової ситуації при спробі повернення методом класу В об’єкта класу А.

  9. Клас В є похідним від класу А. Визначити обробник виняткової ситуації при спробі ініціалізації об’єкта класу В об’єктом класу А.

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

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

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

  13. Побудувати клас-годинник, який має поля для збереження годин (0…23), хвилин (0…59) та секунд (0…59). Визначити обробник виняткової ситуації, якщо створюється об’єкт-годинник з недопустимим значенням годин, хвилин або секунд.

  14. Визначити обробник виняткової ситуації, який перевіряє правильність ділення чисел.

  15. Визначити обробник виняткової ситуації на перетворення об’єкта класу у значення цілочисельного типу.

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

  1. Коли застосовують виключення і які для цього засоби Ви знаєте?

  2. Що таке обробник виняткових ситуацій (виключень)?

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

  4. Як повторно згенерувати виключення, якщо обробник не може повністю обробити дане виключення?

  5. Яка функція викликається, якщо виключення згенеровано, але не перехвачено?

  6. Яка користь від віртуальних функцій при обробці виняткових ситуацій в класах виключень?

  7. Що таке специфікація виключень?

  8. Чи можна виключення використовувати в конструкторах і деструкторах? Обґрунтуйте.

Лабораторна робота №10. Стандартні потокові класи

МЕТА РОБОТИ: навчитись контролювати потоки, освоїти механізм перезавантаження операцій вставки і вилучення з потоку при роботі з класами.

10.1. Програма роботи

10.1.1 Отримати завдання.

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

10.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

10.1.4. Оформити електронний звіт про роботу та захистити її.

10.2. Вказівки до виконання роботи

10.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 10.5 і записує його до звіту.

10.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 10.4.

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

10.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

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

10.3. Теоретичні відомості

У мові програмування C++ механізм введення-виведення потокової інформації функціонує з використанням логічного інтерфейсу, що іменується потоком. Потік (stream) – це загальний логічний інтерфейс з різними пристроями, з яких складається комп'ютер. У мові програмування C++ міститься ряд вбудованих однобайтових (8-бітових) потоків (cin, cout, cerr і clog), які автоматично відкриваються, як тільки програма починає виконуватися. Як уже зазначалося вище, cin – це стандартний вхідний, а cout – стандартний вихідний потік. Потоки cerr і clog (вони призначені для виведення інформації про помилки) також пов'язані із стандартним виведенням даних. Різниця між ними полягає у тому, що потік clog є буферизованим, а потік cerr – ні. За замовчуванням стандартні С++-потоки зв'язуються з монітором, але програмним способом їх можна перенаправити на інші зовнішні пристрої або дискові файли.

С++-система введення-виведення використовує заголовок <iostream>, у якому для підтримки операцій введення-виведення даних визначена достатньо складна ієрархія класів. Ця ієрархія починається з системи шаблонних класів. Маючи шаблонний клас, можна створювати його конкретні примірники. у мові програмування C++ передбачено вдаліший спосіб виконання операцій введення-виведення даних "класових" даних – шляхом перевантаження операторів введення-виведення даних "<<" і ">>".

Оператор "<<" виводить інформацію у потік, а оператор ">>" вводить інформацію з потоку. Перевантажені оператори виведення-виведення даних не можуть бути функціями-членами класу, а щоб отримати доступ до закритих членів класу їх варто зробити дружніми.

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

class kooClass { // Оголошення класового типу

int x, y, z; // Тривимірні координати

public:

kooClass(int a, int b, int c) { x = a; y = b; z = c;}

friend ostream &operator<<(ostream &stream, kooClass obj);

friend istream &operator>>(istream &stream, kooClass &obj);

};

// Відображення тривимірних координат x, y, z

// Перевантажений оператор виведення даних для класу kooClass

ostream &operator<<(ostream &stream, kooClass obj)

{

stream << obj.x << ", ";

stream << obj.y << ", ";

stream << obj.z << "\n";

return stream; // Повертає посилання на параметр stream

}

// Прийняття тривимірних координат x, y, z

// Перевантажений оператор введення даних для класу kooClass

istream &operator>>(istream &stream, kooClass &obj)

{

cout << "Введіть координати x, y і z: ";

// Перевантажений оператор введення даних

stream >> obj.x >> obj.y >> obj.z;

return stream; // Повертає посилання на параметр stream

}

int main()

{

kooClass A_ob(1, 2, 3);

cout << A_ob; // Перевантажений оператор виведення даних

cin >> A_ob; // Перевантажений оператор введення даних

cout << A_ob; // Перевантажений оператор виведення даних

cout<<Cyr("Натиснiть будь-яку клавiшу!");

while(!kbhit());

}

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

10.4. Зразок виконання роботи

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

Кожен запис бази даних має містити такі відомості про співробітника:

  • прізвище і ініціали;

  • рік поступлення на роботу;

  • оклад.

Критерій пошуку: співробітники з окладом, що перевищує деяку задану величину.

Розв'язання задачі почнемо з виявлення понять/класів і їх фундаментальних взаємозв'язків. В даному випадку першим поняттям є база даних, і, отже, для моделювання цього поняття нам знадобиться клас, який зрозуміло назвати DBase. Об'єкт типу DBase(тобто сама база даних) повинен містити деяку сукупність або колекцію інших об'єктів, відповідних записам бази даних. Для моделювання поняття запис бази даних введемо клас Man. Очевидно, що взаємовідношення між вказаними класами відноситься до типу "DBase has а Man".

На другому етапі необхідно уточнити класи, визначивши основні поля і набір операцій над ними. Почнемо з класу DBase. Питання перше, який потрібно вирішити: яку структуру даних доцільно використовувати для зберігання колекції записів. Оскільки об'єм бази даних невеликий3, виберемо найпростіше розв'язання – масив об'єктів типу Man. Очевидно, що в конструкторі класу DBase необхідно передбачити динамічне виділення пам'яті для необхідної кількості об'єктів типу Man, а в деструкторі – звільнення цієї пам'яті. Адресу початку масиву об'єктів буде представлено полем Man* pMan|.

З умови задачі з'ясовуємо також, що у класі необхідно мати метод InitInput() для первинного введення інформації в базу даних і метод SearchPayNotLess() для пошуку співробітників з окладом, що перевищує деяку задану величину. Для контролю правильності введення початкових даних нам стане в нагоді ще один метод – Show(), що забезпечує виведення на екран вмісту бази даних.

Тепер розберемося з класом Man. Для зберігання інформації, що відноситься до одного співробітника, буде потрібно наступні поля:

  • char* pName – адреса рядка, що містить прізвище і ініціали;

  • int come_year – рік поступлення на роботу;

  • double pay – величина окладу.

Конструктор класу повинен виділяти пам'ять для зберігання вказаного рядка, а деструктор – звільняти цю пам'ять. Для розв'язання другої підзадачі (пошук інформації) додамо у клас метод доступу GetPay(). І нарешті, для класу Man потрібно передбачити перезавантаження операції витягання, щоб забезпечити первинне введення інформації з клавіатури в методі InitInput() класу DBase, і операцію вставлення, яка буде використана в методі Show() класу DBase. Обидві операції будуть реалізовані як зовнішні дружні функції.

Іноді під час розв'язання задачі зручно використовувати зовнішні функції, що не є членами класів. Зазвичай ці функції виконують якусь рутинну роботу і можуть бути викликані як з методів класів, так і з основної функції. Типовий приклад – введення значень із стандартного потоку cin із захистом від ненавмисних помилок користувача. Тему оброблення помилок потоків ми зачіпали на початку лабораторної роботи; тепер прийшов час показати можливе практичне вирішення проблеми. Почнемо реалізації перезавантаженої операції >> для класу Man:

istream& operator >>(istream& in, Man& obj) {

//.........................

in >> obj.come_year;

in >> obj.pay;

return in;

}

Якщо у момент виконання оператора in >> obj.come_year; користувач введе замість цілого числа якийсь довільний рядок символів, то програма "зламається". Вашому замовнику напевно не сподобається така поведінка програми. Аналогічна проблема є і під час введення дійсного числа в наступному операторі.

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

Розв'язання задачі, в якій реалізовані розглянуті концепції, є багатофайловий проект, що містить файли DBase.h, DBase.срр|, Man.h, Man.срр|, GetFunc.h, GetFunc.cpp і lab9.cpp:

DBase.h

#pragma once

class DBase {

public:

DBase(int);

~DBase();

void InitInput();

void Show();

void SearchPayNotLess(double);

private:

Man* pMan;

int nRecords;

};

DBase.cpp

#include "StdAfx.h"

#include "Man.h"

#include "DBase.h"

using namespace std;

DBase::DBase(int nRec): nRecords(nRec), pMan(new Man[nRec]) {}

DBase::~DBase() { if(pMan) delete [] pMan;}

void DBase::InitInput() {

for(int i = 0; i < nRecords; i++)

cin >> *(pMan + i); // 1

}

void DBase::Show() {

cout << " == == == == == == == == == == == == == == == == " << endl;

cout << "Вмiст бази даних:" << endl;

for(int i = 0; i < nRecords; i++)

cout << *(pMan + i); // 2

}

void DBase::SearchPayNotLess(double anyPay) {

bool not_found = true;

for(int i = 0; i<nRecords; i++)

if((pMan+i)->GetPay()>=anyPay) {

cout << *(pMan+i);

not_found = false;

}

if(not_found) cout << "Таких спiвробiтникiв немає." << endl;

}

Man.h

#pragma once

#include <iostream>

#include <iomanip>

using namespace std;

const int l_name = 30;

class Man {

public:

Man(int lName = 30);

~Man();

double GetPay() const;

// Операція витягання (введення)

friend istream& operator >>(istream&, Man&);

// Операція вставлення (виведення)

friend ostream& operator <<(ostream&, Man&);

private:

char* pName;

int come_year;

double pay;

};

Man.cpp

#include "StdAfx.h"

#include "Man.h"

#include "GetFunc.h"

Man::Man(int lName) { pName = new char[lName + 1];}

Man::~Man() { if(pName) delete [] pName;}

double Man::GetPay() const { return pay;}

// Операція витягання (введення)

istream& operator >>(istream& in, Man& ob) {

setlocale( LC_ALL,"Ukrainian" );

cout << "\n Введiть данi у форматi" << endl;

cout << "Прiзвище I.Б. <Enter> Рiк поступлення <Enter>";

cout << "Оклад <Enter>:" << endl;

in.getline(ob.pName, l_name);

ob.come_year = GetInt(in); // 3

ob.pay = GetDouble(in); // 4

return in;

}

// Операція вставлення (виведення)

ostream& operator <<(ostream& out, Man& ob) {

out << setw(30) << setiosflags(ios::left);

out << ob.pName << " ";

out << ob.come_year << " ";

out << ob.pay << endl;

return out;

}

GetFunc.h

#pragma once

#include <iostream>

using namespace std;

int GetInt(istream&); // Введення цілого числа

double GetDouble(istream&); // Введення дійсного числа

GetFunc.cpp

#include "StdAfx.h"

#include "GetFunc.h"

#include "Man.h"

// ------------- Bведення цілого числа

int GetInt(istream& in) {

int value;

while(true) {

in >> value; // 5

if(in.peek() == '\n') { //6

in.get(); // 7

break;

}

else {

cout << "Повторiть введення (очiкується цiле число):"

<< endl; // 8

in.clear(); // 9

while(in.get() != '\n') {}; // 10

}

}

return value;

}

// -------------- Введення дійсного числа

double GetDouble(istream& in) {

double value;

while(true) {

in >> value;

if(in.peek() == '\n') {

in.get();

break;

}

else {

cout << "Повторiть введення(очiкується дiйсне число):" << endl;

in.clear();

while(in.get() != '\n') {};

}

}

return value;

}

lab9.cpp

#include "stdafx.h"

#include "Man.h"

#include "GetFunc.h"

#include "DBase.h"

#include <conio.h>

int main() {

const int nRecord = 3;

double any_pay;

DBase dBase(nRecord);

dBase.InitInput();

dBase.Show();

cout << "Введення даних завершене." << endl;

cout << " == == == == == == == == == == == == == == == == " << endl;

cout << "Пошук спiвробiтникiв, чий оклад не менше заданої величини." << endl;

cout << "\n Введiть величину окладу"<< endl;

any_pay = GetDouble(cin);

dBase.SearchPayNotLess(any_pay);

cout<<"Натиснiть будь-яку клавiшу!";

while(!kbhit());

}

Зверніть увагу на наступні моменти.

1. У реалізації методу InitInput() перезавантажена для класу Man операція витягання застосовується до об'єкта, що задається виразом *(pMan + i), тобто до об'єкта, адреса якого є pMan + i (оператор 1).

2. Аналогічна адресація об'єкта для операції вставлення використана в методі Show() оператор 2.

3. У реалізації перезавантаженої операції витягання (файл Man.срр) зверніть увагу на операторів 3 і 4, у яких викликаються функції GetInt() і GetDouble(), призначені для введення із стандартного потоку цілих і дійсних чисел відповідно.

4. Реалізація функцій GetInt() і GetDouble() знаходиться у файлі GetFunc.cpp. Розглянемо детально першу з них. Введення цілого числа організоване усередині нескінченного циклу while таким чином.

  • Інформація читається з вхідного потоку оператором 5. Якщо в буфері типу streambuf, пов'язаному з потоком in, знаходиться зображення цілого числа, що завершується символом перекладу рядка '\n', то після закінчення операції витягання в буфері залишиться тільки символ '\n'. Оператор 6 перевіряє цю умову, використовуючи метод peek(). Якщо перевірка завершилася успішно, оператор 7 очищає вхідний буфер від символу '\n', після чого відбувається вихід з циклу while з подальшим поверненням з функції значення value. Якщо ж введена інформація не є коректним зображенням цілого числа, то виконуються три дії:

  • оператор 8 виводить повідомлення про це, пропонуючи повторити введення;

  • скидаються прапори помилок для потоку in (оператор 9);

  • за допомогою внутрішнього циклу while з вхідного буфера витягуються всі символи, аж до символу '\n' (оператор 10). Зовнішній цикл while повторюється спочатку.

  • Функція GetDouble() працює аналогічно.

5. Функція main() (файл Main.cpp) нічого особливого не представляє. Алгоритм прозорий і сприймається без додаткових пояснень завдяки виразним іменам методів.

6. Давайте повторимо основні моменти цієї лабораторної роботи.

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

  • Введення-виведення форматоване і неформатоване. Для форматованого введення-виведення використовуються перезавантажені операції << і >>, для неформатованого – методи стандартних класів.

  • Управління форматуванням виконується за допомогою маніпуляторів і методів стандартних класів.

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

  • Для забезпечення безпечного введення необхідно діагностувати можливі помилки. При цьому використовуються прапори стану потоку і/або методи peek, get і clear.

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

Рис. 1. Діаграма класів та реалізація програми

10.5. Індивідуальні завдання

Варіант 1. Визначити клас з іменем STUDENT, що містить наступні поля:

  • прізвище і ініціали;

  • номер групи;

  • успішність (масив з п'яти елементів).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу STUDENT.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з десяти об'єктів типу STUDENT;

  • записи повинні бути впорядковані за збільшенням номери групи;

  • виведення на дисплей прізвищ і номерів груп для всіх студентів, включених у масив, якщо середній бал студента більший за 4.0;

  • якщо таких студентів немає, вивести відповідне повідомлення.

Варіант 2. Визначити клас з іменем STUDENT, що містить наступні поля:

  • прізвище і ініціали;

  • номер групи;

  • успішність (масив з п'яти елементів).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу STUDENT.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з десяти об'єктів типу STUDENT;

  • записи повинні бути впорядковані за збільшенням середнього балу;

  • виведення на дисплей прізвищ і номерів груп для всіх студентів, що мають оцінки 4 і 5;

  • якщо таких студентів немає, вивести відповідне повідомлення.

Варіант 3. Визначити клас з іменем STUDENX, що містить наступні поля:

  • прізвище і ініціали;

  • номер групи;

  • успішність (масив з п'яти елементів).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу STUDENT.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з десяти об'єктів типу STUDENT;

  • записи повинні бути впорядковані за абеткою;

  • виведення на дисплей прізвищ і номерів груп для всіх студентів, що мають хоча б одну оцінку 2;

  • якщо таких студентів немає, вивести відповідне повідомлення.

Варіант 4. Визначити клас з іменем AEROFLOT, що містить наступні поля:

  • назва пункту призначення рейсу;

  • номер рейсу;

  • тип літака.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу AEROFLOT.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з семи об'єктів типу AEROFLOT;

  • записи повинні бути впорядковані за збільшенням номери рейсу;

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

  • якщо таких рейсів немає, то необхідно вивести на дисплей відповідне повідомлення;

Варіант 5. Визначити клас з іменем AEROFLOT, що містить наступні поля:

  • назва пункту призначення рейсу;

  • номер рейсу;

  • тип літака.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу AEROFLOT.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з семи об'єктів типу AEROFLOT;

  • записи повинні бути розміщені в алфавітному порядку за назвами пунктів призначення;

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

  • якщо таких рейсів немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 6. Визначити клас з іменем WORKER, що містить наступні поля:

  • прізвище і ініціали працівника;

  • назва посади;

  • рік поступлення на роботу.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу WORKER.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з десяти об'єктів типу WORKER;

  • записи повинні бути розміщені за абеткою;

  • виведення на дисплей прізвищ працівників, чий стаж роботи в організації перевищує значення, введене з клавіатури;

  • якщо таких працівників немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 7. Визначити клас з іменем TRAIN, що містить наступні поля:

  • назва пункту призначення;

  • номер потягу;

  • час відправлення.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу TRAIN.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу TRAIN;

  • записи повинні бути розміщені в алфавітному порядку за назвами пунктів призначення;

  • виведення на екран інформації про потяги, що відправляються після введеного з клавіатури часу;

  • якщо таких потягів немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 8. Визначити клас з іменем TRAIN, що містить наступні поля:

  • назва пункту призначення;

  • номер потягу;

  • час відправлення.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу TRAIN.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з шести об'єктів типу TRAIN;

  • записи повинні бути впорядковані за часом відправлення потягу;

  • виведення на екран інформації про потяги, що прямують в пункт, назва якого введена з клавіатури;

  • якщо таких потягів немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 9. Визначити клас з іменем TRAIN, що містить наступні поля:

  • назва пункту призначення;

  • номер потягу;

  • час відправлення.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу TRAIN.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу TRAIN;

  • записи повинні бути впорядковані по номерах потягів;

  • виведення на екран інформації про потяг, номер якого введений з клавіатури;

  • якщо таких потягів немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 10. Визначити клас з іменем MARSH, що містить наступні поля:

  • назва початкового пункту маршруту;

  • назва кінцевого пункту маршруту;

  • номер маршруту.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу MARSH.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу MARSH;

  • записи повинні бути впорядковані по номерах маршрутів;

  • виведення на екран інформації про маршрут, номер якого введений з клавіатури;

  • якщо таких маршрутів немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 11. Визначити клас з іменем MARSH, що містить наступні поля:

  • назва початкового пункту маршруту;

  • назва кінцевого пункту маршруту;

  • номер маршруту.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу MARSH.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу MARSH;

  • записи повинні бути впорядковані по номерах маршрутів;

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

  • якщо таких маршрутів немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 12. Визначити клас з іменем NOTE, що містить наступні поля:

  • прізвище, ім'я;

  • номер телефону;

  • день народження (масив з трьох чисел).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу NOTE.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу NOTE;

  • записи повинні бути впорядковані по датах днів народження;

  • виведення на екран інформації про людину, номер телефону якого введений з клавіатури;

  • якщо такого немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 13. Визначити клас з іменем NOTE, що містить наступні поля:

  • прізвище, ім'я;

  • номер телефону;

  • день народження (масив з трьох чисел).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу NOTE.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу NOTE;

  • записи повинні бути розміщені за абеткою;

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

  • якщо таких немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 14. Визначити клас з іменем NOTE, що містить наступні поля:

  • прізвище, ім'я;

  • номер телефону;

  • день народження (масив з трьох чисел).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу NOTE.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу NOTE;

  • записи повинні бути впорядковані по трьох перших цифрах номера телефону;

  • виведення на екран інформації про людину, чиє прізвище введене з клавіатури;

  • якщо такого немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 15. Визначити клас з іменем ZNAK, що містить наступні поля:

  • прізвище, ім'я;

  • знак Зодіаку;

  • день народження (масив з трьох чисел).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу ZNAK.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу ZNAK;

  • записи повинні бути впорядковані по датах днів народження;

  • виведення на екран інформації про людину, чиє прізвище введене з клавіатури;

  • якщо такого немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 16. Визначити клас з іменем ZNAK, що містить наступні поля:

  • прізвище, ім'я;

  • знак Зодіаку;

  • день народження (масив з трьох чисел).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу ZNAK.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу ZNAK;

  • записи повинні бути впорядковані по датах днів народження;

  • виведення на екран інформації про людей, що народилися під знаком, найменування якого введене з клавіатури;

  • якщо таких немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 17. Визначити клас з іменем ZNAK, що містить наступні поля:

  • прізвище, ім'я;

  • знак Зодіаку;

  • день народження (масив з трьох чисел).

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу ZNAK.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу ZNAK;

  • записи повинні бути впорядковані по знаках Зодіаку;

  • виведення на екран інформації про людей, що народилися в місяці, значення якого введене з клавіатури;

  • якщо таких немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 18. Визначити клас з іменем PRICE, що містить наступні поля:

  • назва продукції;

  • назва магазина, у якому продається продукція;

  • вартість продукції в гривнях.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу PRICE.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу PRICE;

  • записи повинні бути розміщені в алфавітному порядку за назвами продукції;

  • виведення на екран інформації про продукція, назва якого введена з клавіатури;

  • якщо такої продукції немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 19. Визначити клас з іменем PRICE, що містить наступні поля:

  • назва продукції;

  • назва магазина, у якому продається продукція;

  • вартість продукції в гривнях.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу PRICE.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу PRICE;

  • записи повинні бути розміщені в алфавітному порядку за назвами магазинів;

  • виведення на екран інформації про продукція, що продаються в магазині, назва якого введена з клавіатури;

  • якщо такого магазина немає, то необхідно вивести на дисплей відповідне повідомлення.

Варіант 20. Визначити клас з іменем ORDER, що містить наступні поля:

  • розрахунковий рахунок платника;

  • розрахунковий рахунок одержувача;

  • перерахована сума в гривнях.

Визначити методи доступу до цих полів і перезавантажені операції витягання і вставлення для об'єктів типу ORDER.

Потрібно розробити програму, що виконує такі дії:

  • введення з клавіатури даних у масив, що складається з восьми об'єктів типу ORDER;

  • записи повинні бути розміщені в алфавітному порядку по розрахункових рахунках платників;

  • виведення на екран інформації про суму, зняту з розрахункового рахунку платника, введеного з клавіатури;

  • якщо такого розрахункового рахунку немає, то необхідно вивести на дисплей відповідне повідомлення.

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

  1. Для чого використовують буфер при роботі з потоками?

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

  3. Які класи вводу/виводу називають стандартними?

  4. Для чого призначені маніпулятори?

  5. Яке поле передбачено в базовому класі ios для відстежування помилок?

  6. Чому операції << i >> не можуть бути елементами створеного класу, а тільки дружніми функціями до нього?

  7. На які три групи поділяють маніпулятори класу ios?

  8. Що таке параметризований маніпулятор?

  9. У яких файлах міститься визначення і реалізація параметризованого маніпулятора?

Лабораторна робота №11. Файлові і рядкові потоки

МЕТА РОБОТИ: навчитись контролювати файлові потоки, освоїти механізм запису і зчитування даних із файлу в різних режимах.

11.1. Програма роботи

11.1. Отримати завдання.

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

11.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

11.1.4. Оформити електронний звіт про роботу та захистити її.

11.2. Вказівки до виконання роботи

11.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 11.5 і записує його до звіту.

11.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 11.4.

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

11.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • вміст текстових файлів, які використовуємо в програмі для роботи та результати реалізації програми;

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

11.3. Теоретичні відомості

Файлові операції введення-виведення даних можна реалізувати після внесення у програму заголовка <fstream>, у якому визначено всі необхідні для цього класи і значення. Створивши потік, його потрібно пов'язати з файлом. Це можна зробити за допомогою функції open(), причому у кожному з трьох потокових класів є своя функція-член open(). Їх прототипи мають такий вигляд:

void ifstream::open(const char *filename,

ios::openmode mode = ios::in);

void ofstream::open(const char * filename,

ios::openmode mode = ios::out | ios::trunc);

void fstream::open(const char *filename,

ios::openmode mode = ios::in | ios::out);

У цих записах елемент filename означає ім'я файлу, яке може містити специфікатор шляху, який вказує доступ до нього. Елемент mode називається специфікатором режиму, який визначає спосіб відкриття файлу. Він повинен приймати одне або декілька значень перерахунку openmode, який визначено у класі ios:

  • ios::арр – приєднує до кінця файлу усі дані, що виводяться;

  • ios::ate – пошук потрібних даних починатиметься з кінця файлу;

  • ios::binary – відкриває файл у двійковому режимі;

  • ios::inзабезпечує відкриття файлу для введення даних;

  • ios::out забезпечує відкриття файлу для виведення даних

  • ios::trunc – призводить до руйнування вмісту файлу.

Декілька значень перерахунку openmode можна об'єднувати за допомогою логічного додавання (АБО).

За замовчуванням усі файли відкриваються в текстовому режимі.

Щоб закрити файл, використовується функція-член close().

11.4. Зразок виконання роботи

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

Визначимо слово в тексті як послідовність алфавітно-цифрових символів, після яких слідує або знак пунктуації, або роздільник. Як роздільники можуть виступати один або декілька пропусків, один або декілька символів табуляції '\t' і символ кінця рядка '\n'.

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

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

bool equal(const string& cw, const string& w);

яка повертає значення true, якщо поточне слово cw співпадає із заданим словом w з точністю до знаку пунктуації, або false – інакше.

Маючи таку функцію, дуже просто скласти алгоритм основного циклу:

  • прочитати чергове слово;

  • якщо воно співпадає із заданим словом w (з точністю до знаку пунктуації), то збільшити на одиницю значення лічильника count.

Зверніть увагу на реалізацію функції equal() і, зокрема, на використання операції складання для додавання в кінець рядка w одного із знаків пунктуації.

#include "stdafx.h"

#include <fstream>

#include <string>

#include <iostream>

#include <conio.h>

#include <stdlib.h>

using namespace std;

bool equal(const string& cw, const string& w) {

char punct[] ={'.',',','?','!'};

if(cw == w) return true;

for(int i = 0; i<sizeof(punct); ++i)

if(cw ==w+punct[i]) return true;

return false;

}

int main() {

string word, curword;

setlocale( LC_ALL,"Ukrainian" );

cout << " Введiть слово для пошуку: ";

cin >> word;

ifstream fin("infile.txt", ios::in);

if(! fin) { cout << "Помилка вiдкриття файлу." << endl;

return 1; }

int count = 0;

while(!fin.eof()) {

fin >> curword;

if(equal(curword, word)) count++;

}

cout << "Кiлькiсть входжень слова: " << count << endl;

cout<<"Натиснiть будь-яку клавiшу!";

while(!kbhit());

}

Рис. 1. Реалізація програми і вміст текстового файлу, з якого зчитувалась інформація

11.5. Індивідуальні завдання

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  2. Який потік необхідно відкрити для роботи з файловими операціями?

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

  4. В якому режимі відкриваються файли за замовчуванням?

  5. Як перевірити чи відкритий потік і файл?

  6. Яка функція використовується для отримання кількості зчитаних символів за останню операцію?

  7. Як працює оператор >> при зчитуванні рядків?

  8. Яка різниця між функцією get() i getline()?

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

  10. Як можна перевірити статус введення-виведення?

  11. Які функції використовуються для отримання доступу до вмісту файлу в довільному порядку (не послідовно байт за байтом)?

Лабораторна робота №12. Стандартна бібліотека шаблонів STL, контейнери та ітератори

МЕТА РОБОТИ: засвоїти технологію узагальненого об’єктного програмування з використанням бібліотеки стандартних шаблонів (STL) мови C++ для роботи з вбудованими і користувацькими типами даних.

12.1. Програма роботи

12.1.1. Отримати завдання.

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

12.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

12.1.4. Оформити електронний звіт про роботу та захистити її.

12.2. Вказівки до виконання роботи

12.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 12.5 і записує його до звіту.

12.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 12.4.

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

12.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

  • діаграма класів і варіантів використання;

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

12.3. Теоретичні відомості

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

Склад STL. Ядро бібліотеки утворять три елементи: контейнери, алгоритми й ітератори.

Контейнери (containers) – це об'єкти, призначені для зберігання інших елементів. Наприклад, вектор, лінійний список, множина.

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

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

Ітератори (iterators) – це об'єкти, які стосовно контейнера відіграють роль покажчиків. Вони дозволяють одержати доступ до вмісту контейнера приблизно так само, як покажчики використовуються для доступу до елементів масиву.

З ітераторами можна працювати так само, як з вказівниками. До них можна застосувати операції *, инкремента, декремента. Типом ітератора оголошується тип iterator, що визначений у різних контейнерах.

Існує п'ять типів ітераторів:

1. Ітератори введення (input_iterator) підтримують операції рівності, разыменования й инкремента.

==, !=, *i, ++i, i++, *i++

Спеціальним випадком ітератора введення є istream_iterator.

2. Ітератори виведення (output_iterator) підтримують операції разыменования, припустимі тільки з лівої сторони присвоювання, і инкремента.

++i, i++, *i=t, *i++=t

Спеціальним випадком ітератора виводу є ostream_iterator.

3. Односпрямовані Ітератори (forward_iterator) підтримують всі операції ітераторів уведення/виводу й, крім того, дозволяють без обмеження застосовувати присвоювання.

==, !=, =, *i, ++i, i++, *i++

4. Двонаправлені Ітератори (biderectional_iterator) мають всі властивості forward-ітераторів, а також мають додаткову операцію декремента (--i, i--, *i--), що дозволяє їм проходити контейнер в обох напрямках.

5. Ітератори довільного доступу (random_access_iterator) мають всі властивості biderectional-ітераторів, а також підтримують операції порівняння й адресної арифметики, тобто безпосередній доступ по індексі.

i+=n, i+n, i-=n, i-n, i1-i2, i[n], i1<i2, i1<=i2, i1>i2, i1>=i2

В STL також підтримуються зворотні Ітератори (reverse iterators). Зворотними ітераторами можуть бути або двонаправлені Ітератори, або Ітератори довільного доступу, але мають послідовність у зворотному напрямку.

На додачу до контейнерів, алгоритмів та ітераторів в STL підтримується ще кілька стандартних компонентів. Головними серед них є розподільники пам'яті, предикати й функції порівняння.

У кожного контейнера є визначений для нього розподільник пам'яті (allocator), що управляє процесом виділення пам'яті для контейнера.

За замовчуванням розподільником пам'яті є об'єкт класу allocator. Можна визначити власний розподільник.

У деяких алгоритмах і контейнерах використовується функція особливого типу, називана предикатом. Предикат може бути унарним і бінарним. Значення, що повертає: істина або неправда. Точні умови одержання того або іншого значення визначаються програмістом. Тип унарних предикатів UnPred, бінарних – BinPred. Тип аргументів відповідає типу об'єктів, що зберігаються в контейнері.

Визначено спеціальний тип бінарного предиката для порівняння двох елементів. Він називається функцією порівняння (comparison function). Функція повертає істину, якщо перший елемент менше другого. Типом функції є тип Comp.

Особливу роль в STL грають об'єкти-функції.

Об'єкти-функції ( це екземпляри класу, у якому визначена операція «круглі дужки» (). У ряді випадків зручно замінити функцію на об'єкт-функцію. Коли об'єкт-функція використовується як функція, то для її виклику використовується operator ().

Класи-контейнери. В STL визначені два типи контейнерів: послідовності й асоціативні.

Ключова ідея для стандартних контейнерів укладається в тім, що коли це представляється розумним, вони повинні бути логічно взаємозамінними. Користувач може вибирати між ними, ґрунтуючись на міркуваннях ефективності й потреби в спеціалізованих операціях. Наприклад, якщо часто потрібен пошук по ключу, можна скористатися map (асоціативним масивом). З іншого боку, якщо переважають операції, характерні для списків, можна скористатися контейнером list. Якщо додавання й видалення елементів часто проводиться в кінці контейнера, варто подумати про використання черги queue, черги із двома кінцями deque, стека stack. За замовчуванням користувач повинен використати vector; він реалізований, щоб добре працювати для самого широкого діапазону завдань.

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

В STL визначені наступні класи-контейнери (у кутових дужках зазначені заголовні файли, де визначені ці класи):

bitset

множина бітів <bitset.h>

vector

динамічний масив <vector.h>

list

лінійний список <list.h>

deque

двостороння черга <deque.h>

stack

стік <stack.h>

queue

черга <queue.h>

priority_queue

черга із пріоритетом <queue.h>

map

асоціативний список для зберігання пар ключ / значення, де з кожним ключем зв'язане одне значення <map.h>

multimap

з кожним ключем зв'язано два або більше значення <map.h>

set

множина <set.h>

multiset

множина, у якому кожний елемент не обов'язково унікальний <set.h>

Огляд операцій

Типи

value_type тип елемента

allocator_type тип розподільника пам'яті

size_type тип індексів, лічильника елементів і т.д.

iterator поводиться як value_type*

reverse_iterator переглядає контейнер у зворотному порядку

reference поводиться як value_type&

key_type тип ключа (тільки для асоціативних контейнерів)

key_compare тип критерію порівняння (тільки для асоціативних контейнерів)

mapped_type тип відображеного значення

Ітератори

begin() вказує на перший елемент

end() указує на елемент, що випливає за останнім

rbegin() вказує на перший елемент у зворотній послідовності

rend() вказує на елемент, що випливає за останнім у зворотній послідовності

Доступ до елементів

front() посилання на перший елемент

back() посилання на останній елемент

operator[] (i)доступ по індексі без перевірки

at(i) доступ по індексі з перевіркою

Включення елементів

insert(p,x) додавання х перед елементом, на який указує р

insert(p,n,x) додавання n копій х перед р

insert(p,first,last) додавання елементів з [first:last] перед р

push_back(x) додавання х у кінець

push_front(x) додавання нового першого елемента (тільки для списків і черг із двома кінцями)

Видалення елементів

pop_back() видалення останнього елемента

pop_front() видалення першого елемента (тільки для списків і черг із двома кінцями)

erase(p) видалення елемента в позиції р

erase(first,last) видалення елементів з [first:last]

clear() видалення всіх елементів

Інші операції

size() число елементів

empty() контейнер порожній?

Capacity пам'ять, виділена під вектор (тільки для векторів)

reserve(n) виділяє пам'ять для контейнера під n елементів

resize(n) змінює розмір контейнера (тільки для векторів, списків і черг із двома кінцями)

swap(x) обмін місцями двох контейнерів

==, !=, < операції порівняння

Операції присвоювання

operator=(x) контейнеру присвоюються елементи контейнера х

assign(n,x) присвоювання контейнеру n копій елементів х (не для асоціативних контейнерів)

assign(first,last) присвоювання елементів з діапазону [first:last]

Асоціативні операції

operator[](k) доступ до елемента із ключем k

find(k) знаходить елемент із ключем k

lower_bound(k) знаходить перший елемент із ключем k

upper_bound(k) знаходить перший елемент із ключем, більшим k

equal_range(k) знаходить lower_bound (нижню границю) і upper_bound (верхню границю) елементів із ключем k

Контейнер vector-вектор.

Вектор vector в STL визначений як динамічний масив з доступом до його елементів по індексу.

template<class T,class Allocator=allocator<T>>class std::vector{...};

де T – тип призначених для зберігання даних.

Allocator задає розподільник пам'яті, що за замовчуванням є стандартним.

Приклад

vector<int> a;

vector<double> x(5);

vector<char> c(5,'*');

vector<int> b(a); //b=a

Для будь-якого об'єкта, що буде зберігатися у векторі, має бути визначений конструктор за замовчуванням. Крім того, для об'єкта повинні бути визначені оператори < і ==.

Для класу вектор визначені наступні оператори порівняння:

==, <, <=, !=, >, >=.

Крім цього, для класу vector визначається оператор індексу [].

  • Нові елементи можуть включатися за допомогою функцій

insert(), push_back(), resize(), assign().

  • Існуючі елементи можуть видалятися за допомогою функцій

erase(), pop_back(), resize(), clear().

  • Доступ до окремих елементів здійснюється за допомогою ітераторів

begin(), end(), rbegin(), rend(),

  • Маніпулювання контейнером, сортування, пошук у ньому тощо можливо за допомогою глобальних функцій файлу ( заголовка <algorithm.h>.

Асоціативні контейнери (масиви).

Асоціативний масив містить пари значень. Знаючи одне значення, що називається ключем (key), ми можемо дістати доступ до іншим, називаним відображеним значенням (mapped value).

Асоціативний масив можна представити як масив, для якого індекс не обов'язково повинен мати цілочисельний тип:

V& operator[](const K&) повертає посилання на V, що відповідає K.

Асоціативні контейнери - це узагальнення поняття асоціативного масиву.

Асоціативний контейнер map  це послідовність пар (ключ, значення), що забезпечує швидке одержання значення по ключі. Контейнер map надає двонаправлені Ітератори.

Асоціативний контейнер map вимагає, щоб для типів ключа існувала операція “<”. Він зберігає свої елементи відсортованими по ключі так, що перебір відбувається один по одному.

Специфікація шаблона для класу map:

template<class Key,class,class Comp=less<Key>,class Allocator=allocator<pair> >

class std::map

Визначено операцію присвоювання:

map& operator=(const map&);

Визначено наступні операції: ==, <, <=, !=, >, >=.

В map зберігаються пари ключ/значення у вигляді об'єктів типу pair.

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

Типова операція для асоціативного контейнера - це асоціативний пошук за допомогою операції індексації ([]).

mapped_type& operator[](const key_type& K);

Множина set можна розглядати як асоціативні масиви, у яких значення не грають ролі, так що ми відслідковуємо тільки ключі.

template<class,class Cmp=less<T>,class Allocator=allocator<T>>class std::set{...};

Множина, як і асоціативний масив, вимагає, щоб для типу T існувала операція “менше” (<). Воно зберігає свої елементи відсортованими, так що перебір відбувається один по одному.

12.4. Зразок виконання роботи

Створити контейнер вектор розміром 10 цілого типу і наповнити його числами. Вивести його вміст використовуючи ітератор. Створити інший вектор з п’яти елементів рівних одиниці і вивести його вміст використовуючи ітератор. Потім після другого елементу вставити 10 елементів із значенням 9 і вивести його вміст на екран. Після цього знищити вставлені елементи і перевірити це вивівши вміст вектора на екран. Створити ще один вектор з трьох елементів користувацького типу і вивести його вміст на екран.

Student.h

#pragma once

#include <iomanip>

#include <conio.h>

#include <iostream>

#include <cstring>

using namespace std;

class Student

{char prizv[20];

double bal;

public:

Student(){strcpy(prizv, ""); bal=0;}

Student( char * FN,double sbal);

~Student(void);

friend ostream &operator<<(ostream &stream, Student obj);

};

Student.cpp

#include "StdAfx.h"

#include <string.h>

#include <iomanip>

#include <conio.h>

#include <iostream>

#include "Student.h"

using namespace std;

Student::Student( char* FN,double sbal){

strcpy(prizv, FN);

bal=sbal;

}

ostream &operator<< (ostream &stream, Student obj) {

return stream << ("Student ")<<obj.prizv<<" "<<("bal ")<<obj.bal<<" "<<endl;

}

Student::~Student(void)

{

}

Main.cpp

#include "stdafx.h"

#include<iostream>

#include<vector>

#include <string>

#include <conio.h>

#include "Student.h"

using namespace std;

void main()

{ setlocale( LC_ALL,"Ukrainian" );

vector<int> v;

int i;

for(i=0;i<10;i++) v.push_back(i);

cout<<"size="<<v.size()<<"\n";

vector<int>::iterator p=v.begin();

while(p!=v.end())

{ cout<<*p<<" ";p++;}

cout<<endl;

cout<<"Новий вектор"<<endl;

vector<int>w(5,1);

int j;

for(j=0;j<5;j++) cout<<w[j]<<" ";

cout<<endl;

vector<int>::iterator pp=w.begin();

pp+=2;

cout<<"Вставили 10 елементiв зi значенням 9 пiсля 2 елемента"<<endl;

w.insert(pp,10,9);

pp=w.begin();

while(pp!=w.end())

{cout<<*pp<<" "; pp++;}

cout<<endl;

cout<<"Видаляєм всi вставленi елементи"<<endl;

pp=w.begin();

pp+=2;

w.erase(pp,pp+10);

pp=w.begin();

while(pp!=w.end())

{cout<<*pp<<" ";

pp++;}

cout<<endl;

cout <<"Створюємо вектор користувацького типу STUDENT"<<endl;

vector <Student> s(3);

int k;

s[0]=Student("Ivanov",45.9);//

s[1]=Student("Petrov",30.4);//

s[2]=Student("Sudorov",55.6);//,

//висновок

for(k=0;k<3;k++) cout<<s[k];

cout<<endl;

cout <<"Натиснiть будь-яку клавiшу!";

while(!kbhit());

}

Рис. 1. Діаграма класів і реалізація завдання

12.5. Індивідуальні завдання

Завдання 1. Створити об'єкт-контейнер відповідно до варіанта завдання й заповнити його даними, тип яких визначається варіантом завдання.

2. Переглянути контейнер.

3. Змінити контейнер, видаливши з нього одні елементи й замінивши інших.

4. Переглянути контейнер, використовуючи для доступу до його елементів Ітератори.

5. Створити другий контейнер цього ж класу й заповнити його даними того ж типу, що й перший контейнер.

6. Змінити перший контейнер, видаливши з нього n елементів після заданого й додавши потім у нього всі елементи із другого контейнера.

7. Переглянути перший і другий контейнери.

Завдання 2. Виконати те ж саме, але для даних користувацького типу.

Зауваження:

1. При створенні контейнерів у програмі № 2 об'єкти завантажувати з потоку.

2. Для вставки й видалення елементів контейнера в програмі № 2 використати відповідні операції, визначені в класі контейнера.

3. Для вводу-виводу об'єктів користувацького класу варто перевантажити операції “>>” і “<<”.

4. При переміщенні елементів асоціативного контейнера в неасоціативний переміщаються тільки дані (ключі не переміщаються). І навпаки, при переміщенні елементів неасоціативного контейнера в асоціативний повинен бути сформований ключ.

Варіанти завдань

№ п/п

Контейнер

Вбудований тип даних

1

vector

int

2

list

long

3

deque

float

4

stack

double

5

queue

char

6

vector

string

7

map

long

8

multimap

float

9

set

int

10

multiset

char

11

vector

double

12

list

int

13

deque

long

14

stack

float

15

queue

int

16

priority_queue

char

17

map

char

18

multimap

int

19

set

char

20

multiset

Int

21

multimap

long

22

queue

float

23

priority_queue

char

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

  1. Які засоби містить стандартна бібліотека шаблонів?

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

  3. Для чого використовується контейнер STL?

  4. Який зв'язок між контейнерами, літераторами і алгоритмами?

  5. Що таке предикат і що він повертає?

  6. Що потрібно додати до програми, щоб створити контейнер користувацького типу і працювати з ним?

  7. Поясніть як працює контейнер з двоспрямованим послідовним доступом? Наведіть приклад.

  8. Що таке асоціативний контейнер? Наведіть приклад.

Лабораторна робота №13. Стандартна бібліотека шаблонів STL, Алгоритми

МЕТА РОБОТИ: вміти використовувати алгоритми STL для роботи з шаблонними об’єктами цієї ж бібліотеки.

13.1. Програма роботи

13.1.1. Отримати завдання.

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

13.1.3. Підготувати власні коректні вхідні дані (вказати їх формат і значення) і проаналізувати їх.

13.1.4. Оформити електронний звіт про роботу та захистити її.

13.2. Вказівки до виконання роботи

13.2.1. Студент, згідно з індивідуальним номером, вибирає своє завдання з розд. 13.4 і записує його до звіту.

13.2.2. Оголошення класу (структури), основну та відповідні допоміжні функції необхідно запрограмувати так, як це показано у розд. 13.4.

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

13.2.4. Звіт має містити такі розділи:

  • мету роботи та завдання з записаною умовою задачі;

  • коди всіх використовуваних .h і .ccp файлів, а також пояснення до них;

  • результати реалізації програми;

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

13.3. Теоретичні відомості

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

Алгоритми визначені в заголовному файлі <algorithm.h>.

Нижче наведені імена деяких найбільш часто використовуваних функцій-алгоритмів STL.