Методичні вказівки до лабораторної роботи №3 на тему Виключення та їх обробка
« Назад Методичні вказівки до лабораторної роботи №3 з курсу Програмування (мова програмування С) на тему: Виключення та їх обробкаМета роботи: ознайомитись з механізмом обробки виключень Короткі теоретичні відомості 1. Використання assert.h 2. Філософія відновлення після помилок Виключення – виникнення непередбачених помилкових ситуацій, наприклад, ділення на нуль при операціях з плаваючою точкою. Як правило, ці умови завершують програму користувача з системним повідомленням про помилку. С++ дає програмісту можливість відновлювати програму за таких умов і продовжувати її виконання. Використання assert.h Досягнення потрібного результату при написанні програми лише частково можна розглядати, як доказ того, що програма правильна. У більшості випадків імовірність правильного виконання програми залежить в рівній мірі від алгоритму і від введених правильно даних. Тому при написанні програм варто перевіряти чи може виконатись вказаний алгоритм при таких даних. Стандартна бібліотека забезпечує макрокоманду, яка описана в assert.h void assert(int expression); Якщо expression оцінюється як неправильне, то виконання переривається з виведенням діагностики. Підтвердження відкидаються, якщо визначається макрокоманда NDEBUG. Розглянемо приклад конструктору з одним безпечним параметром масиву. vect::vect(int n) { if(n<1) { cerr << “illegal vect size” << n; exit(1); } size=n; p=new int[size]; if (p==NULL) { cerr << “not enough memory” << n; exit(1); } } Це ж саме можна описати як vect::vect(int n){ assert(n > 0); // обумовлена передумова size=n; p=new int[size]; assert(p!=NULL); // обумовлена постумова } Використання assert-тверджень, замінюючих початкові перевірки умов, робить методологію одноріднішою. Іншим фактором такого використання буде те, що методологія assert-твердження не дозволяє повторення або застосування іншої стратегії відновлення для продовження виконання програми. Виключення в С++ С++ забезпечує вбудований механізм обробки помилок, названий обробкою вийняткових ситуацій. Завдяки обробці вийняткових ситуацій можна спростити управління і реакцію на помилки часу виконання. Обробка вийняткових ситуацій в С++ будується за допомогою трьох ключових слів: try, catch, throw. Оператори програми, під час виконання яких ви хочете забезпечити обробку вийняткових ситуацій, розташовуються в блоці try. Якщо вийняткова ситуація (тобто помилка) має місце усередині блоку try, вона генерується (за допомогою throw). Перехоплюється і обробляється вийняткова ситуація за допомогою ключового слова catch. Будь-який оператор, який генерує вийняткову ситуацію, повинен виконуватися усередині блоку try. (Функції, які викликаються усередині блоку try також можуть генерувати вийняткову ситуацію). Будь-яка вийняткова ситуація повинна перехоплюватися оператором catch, який слідує безпосередньо за блоком try, що генерує вийняткову ситуацію. try { // блок try } catch (type1 arg) { // блок catch } catch (type2 arg) { // блок catch } ......... catch (typeN arg) { // блок catch } Блок try повинен містити ту частину програми, в якій ви хочете відстежувати помилки. Це можуть бути декілька операторів усередині однієї функції, так і всі оператори функції main() (що природно викликає відстежування помилок у всій програмі). Коли вийняткова ситуація виникає, вона перехоплюється відповідним їй оператором catсh, який її обробляє. З блоком try може бути пов'язане більше одного оператора catch. Те, який конкретно оператор catch використовується, залежить від типу вийняткової ситуації. Тобто, якщо тип даних, вказаний в операторі catch, відповідає типу вийняткової ситуації, то виконується даний оператор catch. А всі інші оператори блоку try пропускаються. Якщо вийняткова ситуація перехоплена, то аргумент arg набуває її значення. Можна перехопити будь-які типи даних, включаючи і створювані вами типи. Загальна формула оператора throw throw виключна_ситуація; Оператор throw повинен виконуватися або усередині блоку try, або в будь-якій функції, яку цей блок викликає (прямо або побічно). Тут виключна_ситуація - це вийняткова ситуація, що викликається оператором. Зауваження. Якщо ви генеруєте вийняткову ситуацію, для якої немає відповідного оператора catch, може відбутися абнормальне завершення програми. Розглянемо приклад роботи вийняткової ситуації. void main() { try { throw 10; } catch(int i) { cout << " error " << i << endl; } return; } На екран виведеться повідомлення: error 10 С++ має чутливий до контексту механізм обробки особливих ситуацій. Він не призначений для обробки асинхронних виключень. Код С++ дозволяє безпосередньо встановлювати виключення в блоці try, використовуючи вираз throw. Виключення обробляється викликом відповідного обробника, який вибирається із списку обробників, що знаходиться відразу після їх блоку try. Простий приклад цієї методики. vect::vect(int n){ if(n <1) throw(n); p=new int[n]; if(p==NULL) throw(“FREE STORE EXHAUSTED”); } void g() { try { vect а(n),b(n);... } catch(int n) {... } // відстежує всі неправильні розміри catch(char *error) {... } // відстежує перевищення вільної пам'яті } Перший throw() має цілий аргумент і відповідає сигнатурі catch(int n). При передачі неправильного розміру масиву як параметр конструктора очікується, що цей обробник виконає відповідну дію, наприклад, повідомлення про помилку і аварійне припинення роботи. Другий throw() має покажчик на символьний аргумент і відповідає сигнатурі catch (char *error). Філософія відновлення після помилок Відновлення при виникненні помилок - в основному має відношення до правильності написання програми. Обробка виключень близька до відновлення при виникненні помилок і до механізму передачі управління. Слідуючи моделі користувач/виготівник, виготівник повинен гарантувати, що при прийнятному вхідному стані, його програмне забезпечення виконує правильне виведення. На скільки повинно бути вбудоване виявлення і виправлення помилок - справа виготівника. Користувач частіше користується бібліотеками виявлення помилок, тому що так він може ухвалювати рішення щодо того, чи намагатися продовжувати обчислення. Досвід показує, що як правило код програм слабо коментується і важко уявити програму, в якій чітко оброблялися усі можливі варіанти. Якщо при нормальному програмуванні дуже часто виявляються помилки і відбувається переривання - це ознака того, що програма погано обдумана і мала дуже велику кількість прорахунків в первинному вигляді. Порядок виконання роботи В процесі самостійної роботи: 1. Вивчити по методичних вказівках або по іншій літературі методику створення класів та обробку вийняткових ситуацій. 2. Створити клас (з індивідуального завдання) із заданими полями. 3. Створити конструктор без параметрів (для початкової ініціалізації). 4. Створити масив з 5 об'єктів заданого класу. 5. Написати функцію для зміни значень полів (за допомогою посилань). 6. Написати функцію для форматованого виведення всіх класів на екран (впорядкованих по першому полю). 7. Передбачити обробку виняткових ситуацій. 8. Написати звіт по лабораторній роботі. Практична частина Розглянемо приклад написання програми для об’єктів типу телефон. Зробимо визначення типів полів класу і функцій-членів. Наш клас phone (телефон) містить 4 поля: long number (номер телефону), char *data (дата установки телефону), int lock (наявність/відсутність блокіратора), char *name (прізвище абонента). Визначимо для нашого класу конструктор за умовчанням, який дозволить нам заповнити масив об'єктів за допомогою відповідного методу з передачею йому наперед заданих значень. phone() { number=0; data=NULL; lock=0; name=NULL;}; Для виконання умов завдання нам необхідні функції, які б виконували: додавання записів в таблицю, їх виведення і сортування по першому полю. Визначимо дані функції-члени класу в секції private: void change(phone &a,long &numer, char *dat, int &lok, char *nm); - додавання запису. Робочий механізм даної функції практично повністю ідентичний розглянутій раніше функції set, за винятком того, що як передаваного параметра функція одержує ещT і екземпляр класу. Полям цього екземпляра і будуть привласнені значення решти передаваних у функцію значень. void show(); - виведення записів у вигляді таблиці Ця функція виконує переддрукову підготовку даних і власне їх друк на екрані монітора. Вона приводить номер телефону з вигляду 921034 в звичнішій і зрозумілішій формі – 92-10-34, для чого використовується перетворення номера в рядок і розбір рядка з розстановкою дефісів в необхідних позиціях. Також функція show() стежить за тим, чи є блокіратор у абонента чи ні. Якщо є, то виводить на екран не 1, а ТАК, якщо ні - то НЕМАЄ. void sort(); - сортування записів по першому стовпцю. Дана функція виробляє сортування записів по полю number (номер телефону). У програмі, текст якої знаходиться нижче, для зручності використовується меню, а для наочності виконання операцій - масив з 7 об'єктів. #include "stdafx.h" #include <iostream> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <iomanip> #include <assert.h> using namespace std; class phone{ public: long number; char *data; int lock; char *name; phone() {number=0; data=NULL; lock=0; name=NULL;}; }; void change (phone &a,long &numer, char *dat, int &lok, char *nm); void show(); void sort(); phone obj[7]; void change(phone &a,long numer, char *dat, int lok, char *nm) { a.number = numer; a.lock = lok; a.data = new char[strlen(dat)+1]; strcpy(a.data,dat); a.name = new char[strlen(nm)+1]; strcpy(a.name,nm); } void sort() { int i,j; phone temp; try { if (obj[0].data == NULL) throw 100; for (i=0; i<7; i++) for (j=i+1; j<7; j++) if (obj[i].number > obj[j].number) { temp = obj[i]; obj[i] = obj[j]; obj[j] = temp; } } catch (int) { cerr << "Array not filled\n"; } } void show() { int i; cout << " TELEFON: \n"; cout << "----------------------------------------------------------------\n"; cout << " Nomer Data ustanovky Blokirator Prizvyshe abonenta\n"; cout << "----------------------------------------------------------------\n"; char s[10]; for (i=0; i<7; i++) { ltoa(obj[i].number,s,10); if (strlen(s)==6) { cout <<' '<<s[0]<<s[1]<<"-"<<s[2]<<s[3]<<"-"<<s[4]<<s[5]; } else if (strlen(s)==7) { cout << s[0]<<s[1]<<s[2]<<"-"<<s[3]<<s[4]<<"-"<<s[5]<<s[6]; } cout << setw(15) << obj[i].data; if (obj[i].lock == 0) cout << setw(15) << "No"; else if(obj[i].lock == 1) cout << setw(15) << "Yes"; cout << setw(25) << obj[i].name; cout << "\n"; } cout << "----------------------------------------------------------------\n"; } int main() { int r = 0; for (int a=0; !a;) { cout <<"1. Add record\n"; cout <<"2. Sort base\n"; cout <<"3. Show base\n"; cout <<"4. Exit\n"; cout <<"> "; int p; cin>>p; switch(p) { case 1: { change(obj[0],921034, "12.05.99",1,"Ivanov"); change(obj[1],1002010,"17.12.85",0,"Petrov"); change(obj[2],109231, "02.01.80",1,"Sidorov"); change(obj[3],324439, "27.07.94",0,"Antonov"); change(obj[4],1251367, "20.10.01",1,"Maslov"); change(obj[5],173167, "10.01.83",0,"Sokolov"); change(obj[6],134367, "11.06.79",0,"Malahov"); r = 1; break; } case 2: { sort(); break; } case 3: { assert(r); show(); break; } case 4: { a=1; break; } default: { cout << "Try more times..."; getch(); break; } } } } Завдання Описати клас та методи для роботи з наступними класами. Визначити типи полів класу і функцій-членів. Реалізувати методи change(), sort(), show() використовуючи програму-зразок з практичної частини. 1. Книга (жанр, автор, назва, рік видання, ціна) 2. Дисципліна (назва, об’єм годин, форма контролю) 3. Товар (назва, код товару, одиниця виміру, продажна вартість одиниці) 4. Виріб (назва виробу, код виробу, марка металу, вага виробу) 5. Магазин (назва, номер, площа торгових залів, площа складських приміщень) 6. Автомобіль (марка, номерний знак, рік випуску, вартість) 7. Студент (Прізвище, ім’я та по батькові, факультет, група, середній бал успішності) 8. Послуга, що надається (найменування, одиниця виміру, вартість за одиницю, вартість витратних матеріалів за одиницю) 9. Пацієнт (Прізвище, ім’я та по батькові, реєстраційний код, адреса, рік народження, місце роботи) 10. Автомайстерня (марка автомобіля, вартість ремонту, кількість днів в ремонті, номерний знак) 11. Спортсмен (Прізвище, ім’я та по батькові, рік народження, розряд, кількість років в спорті) 12. Країна (назва, столиця, площа території, чисельність населення) 13. Аеропорт (населений пункт, пропускна спроможність, місткість) 14. ЕОМ (тип процесора, частота процесора, об’єм пам'яті, об’єм ЖД) 15. Літак (марка, довжина, розмах крил, висота, номер рейса) 16. Планета (назва, радіус, маса, в якій системі знаходиться) 17. Тварина (назва виду, вага, вік, тип раціону) 18. Годинник (модель, марка, варіант виконання, ціна) 19. Птах (назва, вік, вага, дальність польоту) 20. Будинок (номер будинку, вулиця, кількість під'їздів, кількість поверхів, кількість квартир). Контрольні питання 1. Які особливості щодо свого опису має оператор try? 2. Які особливості щодо свого опису має оператор throw? 3. Що так виключення? 4. Для чого застосовують макрос assert? 5. Чи можна використовувати throwбез try? 6. Чи можна використовувати throwбез catch? 7. Призначення ключового слова finally? 8. Чи є специфічні класи для виключень? З повагою ІЦ "KURSOVIKS"! |