Курсовая работа: Побудова і використання класів
Название: Побудова і використання класів Раздел: Рефераты по информатике Тип: курсовая работа | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Міністерство науки та освіти України Дніпропетровський національний університет Факультет фізики, електроніки та комп’ютерних систем Кафедра автоматизованих систем обробки інформації Курсова робота з дисципліни «Об’єктно-орієнтоване програмування» Тема: Побудова та використання класів. Клас classProgressBar. Виконав: студент групи РС-05 Калиновський К.О. Керівник: доцент кафедри АСОІ Вовк С.М. Дніпропетровськ 2007 Зміст Текст завдання 1. Об’єктно-орієнтоване програмування мовою С++ 1.1 Основні принципи об’єктно-орієнтованого програмування 1.2 Методика розробки програм на основі об’єктно-орієнтованого підходу 1.3 Принципи розробки класів та об’єктів 1.4 Особливості розробки класів мовою С++ 1.5 Розробка класів з використанням технології візуального програмування 2. Розробка класу classProgressBar 2.1 Постановка задачі та обрані методи її розв’язку 2.2 Реалізовані концепції 2.3 Опис класів 2.3.1 Базовий клас classProgressBar 2.3.2 Базовий клас font 2.3.3 Похідні класи horBar, vertBar, roundBar та ringBar 2.4 Методи тестування програми 2.5 Результати виконання програми 3. Висновки 4. Література 5. Додатки Текст завдання Варіант №8. Побудова та використання класів. Клас classProgressBar. Розробити клас classProgressBar, на основі якого можна створювати об'єкти типу "смужка прогресу" і використовувати їх як елементи графічного інтерфейсу в відеорежимі VGA 640x480x16. "Смужка прогресу" представляє собою звичайне горизонтальне віконце зі смужкою, яка заповнюється певним кольором відповідно до обсягу виконаної роботи, та рядком тексту всередині, який вказує на відсоток (процент) виконаної роботи. При роботі об'єктів передбачити можливість встановлення та зміни їх місця розташування на екрані, параметрів рамки віконця, лінійних розмірів, кольорів тексту, фону та заповнення, шрифту тексту, форми смужки (горизонтальна смужка, вертикальна смужка, смужка у формі дуги, круга, тощо), а також наявність звукового супроводження для указівки на 25%, 50%, 75% та 100% завершення роботи. Розробку проводити для операційної системи MS DOS. 1. Об’єктно-орієнтоване програмування мовою С++ 1.1. Основні принципи об’єктно-орієнтованого програмування Об’єктно-орієнтоване програмування (далі ООП) – це технологія програмування, яка базується на класифікації та абстракції об’єктів. ООП акумулює найкращі ідеї, реалізовані в структурному програмуванні та єднає їх з новими потужними концепціями, які дозволяють оптимально організовувати програми. ООП дозволяє розкласти проблему на складові частини. Кожна складова частина становиться самостійним об’єктом, який містить свої власні коди та дані, які належать цьому об’єкту. В цьому випадку вся процедура в цілому спрощується, і програміст отримує можливість оперувати з набагато більшими за об’ємом програмами. В даній курсовій роботі основні концепції ООП реалізуються за допомогою мови програмування високого рівня С++. Усі мови ООП, включаючи С++, базуються на трьох основних концепціях: інкапсуляція, поліморфізм та успадкування. Розглянемо ці концепції. Інкапсуляція (encapsulation) – це механізм, який єднає дані та код, керуючий цими даними, а також захищає одне та друге від зовнішнього впливу або неправильного використання. Якщо поєднати код та дані разом, то отримаємо об’єкт (object). Іншими словами, об’єкт – це те, що підтримує інкапсуляцію. Всередині об’єкта коди та дані можуть бути закритими (private) або відкритими (public). Закриті коди та дані доступні тільки для інших частин цього об’єкта. Закриті коди та дані недоступні для частин програми, які існують за цим об’єктом. Якщо коди та дані є відкритими, то не дивлячись на те що вони задані всередині об’єкта, їх можна використовувати в інших частинах програми. Насправді об’єкт – це змінна визначеного користувачем типу. Таким чином, об’єкт, який єднає код та дані, є складеною змінною. Поліморфізм (polymorphism) – це властивість, яка дозволяє одне й те ж саме ім’я використовувати для розв’язання двох та більше схожих, але технічно різних задач. Метою поліморфізму є використання одного імені для завдання загальних для класу дій. Виконання кожної конкретної дії буде визначатися типом даних. В С++ можна використати одне ім’я функції для множини різних дій. Це називається перевантаженням функцій (functionoverloading). Перевагою поліморфізму є те, що він допомагає знижувати складність програм дозволяючи використовувати той самий інтерфейс для завдання єдиного класу дій. Також можна примінити поліморфізм до операторів. Такий тип поліморфізму називається перевантаженням операторів (operatoroverloading). Ключовим у розумінні поліморфізму є те, що він дозволяє маніпулювати об’єктами різного степеня складності шляхом загального для них стандартного інтерфейсу для реалізації схожих дій. Успадкування (inheritance) –це процес, за допомогою якого один об’єкт може одержувати властивості іншого. Тобто об’єкт може успадковувати основні властивості іншого об’єкта та додавати до них риси, характерні тільки для нього. Успадкування є важливим, тому що воно дозволяє підтримувати концепцію ієрархії класів. Без використання ієрархії класів, для кожного об’єкта треба було б задати усі характеристики, які б повністю його визначали. Але при використанні успадкування можна описати об’єкт шляхом визначення того загального класу (або класів), до яких він відноситься, з тими спеціальними рисами, які роблять об’єкт унікальним. [1] 1.2. Методика розробки програм на основі об’єктно-орієнтованого підходу Розробка програм на мові С++ ведеться з допомогою спеціальних комплексів програм, які мають назву системи програмування та дозволяють створювати програми на конкретній реалізації мови. Процес створення програм включає чотири етапа: 1. Написання та редагування начального тексту програми з запам’ятовуванням її у вигляді начального файлу або модуля. 2. Компіляція програми та отримання її на певній проміжковій мові з запам’ятовуванням її у вигляді об’єктного файлу або модуля. 3. Створення файлу, який виконується або модуля шляхом об’єднання (компоновки) отриманого об’єктного модуля програми з іншими об’єктними модулями стандартних та спеціальних бібліотек. 4. Налагодження програми, яке можна проводити з допомогою спеціального засобу (налагоджувальника) , який полегшує знаходження помилок. Основними компонентами сучасних систем програмування є: · інтегроване середовище програмування; · редактор зв’язків (компоновник); · бібліотеки заголовних файлів; · стандартні та спеціальні бібліотеки; · бібліотеки прикладів програм; · програми-утиліти; · файли документації. Таким чином, загальну схему створення програми можна описати наступною діаграмою. передпроцесорна обробка компіляція компоновка pr.cpppr.objpr.exe *.h, *.cpp *.obj, *.lib Мал. 1. Схема створення модуля, який виконується Інтегроване середовище програмування – це програма, яка містить вмонтований тестовий редактор, підсистему роботи із файлами, систему довідкової допомоги (Help - систему), вмонтований налагоджувальник, підсистему керування компіляцією та редагуванням зв’язків. Початковий модуль програми (ПМ) готується із допомогою внутрішнього або зовнішнього текстового редактору та запам’ятовується в файлі *.cpp. Далі він обробляється передпроцесором та в разі необхідності він з’єднується з підключаємі файли (ПФ). Далі модернізований початковий модуль (ПМ*) обробляється компілятором. Знайдені синтаксичні помилки виправляються та безпомилково скомпільований об’єктний модуль (ОМ) поміщуються в файл *.cpp. Далі об’єктний модуль обробляється компоновником, який приєднує до програми необхідні бібліотечними функціями з бібліотечних файлів (БФ). В результаті отримаємо модуль, який виконується. Програми-утиліти – це допоміжні програми, які можуть бути необхідними при створенні програм. Наприклад, така програма-утиліта як бібліотекар допомагає об’єднувати об’єктні модулі в один файл, який зветься статистичною бібліотекою. [2] 1.3. Принципи розробки класів та об’єктів Сукупність принципів проектування, реалізації та розробки програм, яка базується на абстракції даних, передбачає створення нових типів даних, які з найбільшою повнотою відображають особливості задачі, яка розв’язується. В мові С++ програміст має можливість ввести власні типи даних та визначити операції над ними за допомогою класів. Клас – це похідний структурований тип, введений програмістом на основі вже існуючих типів. Механізм класів дозволяє створювати типи у повно мій відповідності до принципів абстракції даних, тобто клас задає деяку структуровану сукупність типізованих даних та дозволяє визначити набір операцій над цими даними. Клас можна визначити за допомогою конструкції: ключ_класу ім’я_класу {список компонентів}; де ключ_класу – одне з службових слів class, struct, union; ім’я_класу – правильний ідентифікатор; список_компонентів – визначення та описання типізованих даних та функцій, які належать класу. В проекті стандарту мови С++ вказано, що компонентами класу можуть бути дані, функції, класи, бітові поля, дружні функції, дружні класи та імена типів. Приклад описання класу. Клас «комплексне число». structcomplex//варіант класу «комплексне число» { doublereal;//реальна частина doubleimag;//уявна частина //визначення значення комплексного числа voiddefine (doublere = 0.0, doubleim = 0.0) { real = re; imag = im; } //друк значення комплексного числа на екран void display (void) { cout << “real = ” << real << “ ,imag = ” << imag; } }; Отже, клас – це тип, введений програмістом. Кожен тип служить для визначення об’єктів. Для описання об’єкта класу використовується конструкція: ім’я_класу ім’я об’єкту; В об’єкти (класу) входять дані (елементи), відповідні компонентам даних класу. Компонентні функції класу дозволяють обробляти дані конкретних об’єктів класу. Визначення об’єктів класу передбачає виділення ділянки пам’яті та ділення цієї ділянки на фрагменти, відповідні окремим елементам об’єкта, кожен із котрих відображає окремий компонент даних класу. Як тільки об’єкт є визначеним, з’являється можливість звертатися до його компонент, по-перше, за допомогою «кваліфікованих» імен, кожне з яких має формат: ім’я_об’єкта.ім’я_класу::ім’я компоненту Ім’я класу з операцію вказівки області дії «::» звичайно може не використовуватися та дуже часто для доступу к даним конкретного об’єкту заданого класу (як і у випадку структур) використовується уточнене ім’я: ім’я_об’єкту.ім’я_елементу; Інший спосіб доступу до елементів об’єкту деякого класу передбачає використання вказівника на об’єкт класу та операції непрямого вибору компонент («–>»): вказівник_на_об’єкт_класу –> ім’я_елементу; Вказівник на об’єкт класу дозволяє викликати функції, які належать до класу, для обробки даних того об’єкту, який адресується вказівником. Для ініціалізації об’єктів класу в його визначення можна явно включати спеціальну компонентну функцію, яка називається конструктор. Формат визначення конструктора в тілі класу може бути таким: ім’я_класу (список_формальних_параметрів) {оператори_тіла_конструктора}; Приклад конструктора для класу complex: complex (double re = 0.0, double im = 0.0) { real = re; imag = im; } Ім’я цієї компонентної функції за правилами мови С++ повинно збігатися з іменем класу. Така функція автоматично викликається при визначенні або розташуванні в пам’яті за допомогою оператора newкожного об’єкту класу. Конструктор неможна викликати як звичайну компонентну функцію. Для явного виклику конструктора можна використати дві різні синтаксичні форми: ім’я_класу ім’я об’єкту (фактичні_параметри_деструктора); ім’я_класу (фактичні_параметри_деструктора); Перша форма допускається тільки при непорожньому списку фактичних параметрів. Вона передбачає виклик конструктора при визначенні нового об’єкта даного класу: complex ss(10.3, 0.22); //ss.real = 10.3; //ss.imag = 0.22; complex ee(2.345); //ee.real = 2.345; //ee.imag = 0.0 (за замовченням) complexdd();//помилка! Компілятор порахує, що це //прототип функції без параметрів, //який повертає значення типа complex Інша форма явного виклику конструктора приводить до створення об’єкту, який не має імені. Створений таким чином об’єкт без імені можна використовувати у тих виразах, де можна використовувати об’єкт даного класу. Наприклад: complexzz = complex (4.0, 5.0); //zz.real = 4.0; zz.imag = 5.0; Динамічне виділення пам’яті для об’єктів якого-небудь класу створює необхідність у звільнені цієї пам’яті при знищенні об’єкту. Таку можливість забезпечую спеціальний компонент класу – деструктор (знищувач об’єктів) класу. Для нього передбачений стандартний формат: ~ім’я_класу () {оператори тіла деструктора}; Назва деструктору в С++ завжди починається з символа тильда «~», за яким без пропусків та інших роздільних знаків поміщується ім’я класу. У деструктора не може бути параметрів (навіть типу void). Деструктор не має повертає мого значення (навіть типу void). Виклик деструктора виконується неявно, автоматично, як тільки об’єкт класу знищується. [3] 1.4. Особливості розробки класів мовою С++ У відповідності до синтаксису мови С++ кожний компонент класу має статус доступу. Таких статуси три: загальнодоступний (public), власний (private) та захищений (protected).За специфікаторами доступу (public, private, protected) йде двокрапка. Дія специфікаторів на компоненти класу починається з моменту написання до нового специфікатора або до кінця описання класу. Специфікатор доступу privateвикористовується для завдання статусу доступу до елементів даних класу, що дозволяє вирішити проблему захисту даних. Власні дані становляться доступними тільки для методів свого класу. Специфікатор доступу public часто використовується для завдання загальнодоступного доступу методів класу, які організують зв’язок об’єкта даного класу з зовнішнім світом. Статус захищений (protected)використовується в класах при використанні механізму успадкування класів. При відсутності успадкування специфікатор protected еквівалентний специфікатору private. Усі компоненти класу, введені за допомогою ключових слів struct і union є за замовченням загально ступними, а за допомогою ключового слова class – власними, тобто недоступними для зовнішніх викликів. Для заміни статусу доступу компонентів класу, описаних за допомогою ключових слів classта union, необхідно використовувати специфікатори доступу. Класи, описані за допомогою ключового слова union, не можуть використовуватися як базові класи при успадкуванні. У об’єктів, об’явлених на основі подібного класу, для елементів даних виділяється загальне місце в пам’яті. Статус компонентів у таких класів змінити неможна. [2] Одним з найважливіших механізмів в С++ є механізм успадкування. Успадкування в будь-якій сучасній мові програмування виконує дві ролі: з одного боку, попереджає дублювання кодів, а з іншого – допомагає розвивати роботу в необхідному направленні. При успадкуванні обов’язково є клас-родитель та клас-нащадок. В С++ клас-родитель прийнято називати базовим, а клас-нащадок – похідним. Відносини між родительським класом та його нащадками називають ієрархією класів. Простим (або одиночним) називається успадкування, при якому похідний клас має тільки одного родителя. Формально успадкування одного класу от іншого можна завдати наступною конструкцією: Classім’я_класу-нащадника: [модифікатор_доступу]ім’я_базового_класу {тіло_класу} Клас-нащадок успадковує структуру (всі елементи даних) та поведінку (всі функції-методи) базового класу. Модифікатор_доступу визначає доступність елементів базового класу в класі-нащадку. Квадратні дужки говорять о том, що цей модифікатор може бути відсутнім. Цей модифікатор називається модифікатором успадкування. Існують чотири варіанти успадкування: клас від класу, клас від структури, структура від структури та структура від класу. В залежності від модифікаторів доступу при об’яві базового класу та при успадкуванні, доступність об’єктів базового класу із класів-нащадків змінюється. В Таблиці 1 приведені усі варіанти доступності елементів базового класу в похідному класі.
Таблиця 1. Доступ до елементів базового класу в класах-нащадках. Якщо у якості специфікатора доступу записано слово public, то таке успадкування називається відкритим. Відповідно, при використанні модифікатора protected маємо захищене успадкування, а слово private визначає закрите успадкування. Також мова С++ підтримує механізм множинного успадкування. Тобто, один клас-нащадок може мати два та більше класів-родителів. Такий клас-нащадок буде успадковувати дані та методи з усіх класів-родителів відповідно до статусу доступу в класів-родителів. Множинне успадкування можна задати такою конструкцією: Class ім’я_класу-нащадника: [модифікатор_доступу1] ім’я_базового_класу1, [модифікатор_доступу2]ім’я_базового_класу2, ... [модифікатор_доступуN]ім’я_базового_класуN {тіло_класу} [4] Мові С++ включає тау властивість, як поліморфізм – можливість для об’єктів різних класів, зв’язаних з допомогою успадкування, реагувати різними способами при виклику однієї функції-елементу. До найважливіших форм поліморфізму можна віднести: · перевантаження функцій та операцій; · віртуальні функції; · узагальнені функції, або шаблони. Перевантаження функцій та операцій можна визначити як статичний поліморфізм, тому що він підтримується на етапі компіляції. Віртуальні функції відносяться до динамічного поліморфізму, тому що він реалізується при виконанні програм. В С++ дозволяється наявність декількох однойменних функцій, які виконують аналогічні дії над даними різних типів. Наприклад, в програмі визначені дві функції з прототипами: intmax(int, int); floatmax(float, float); В процесі компіляції програми при виклику функцій max() в залежності від типу та числа аргументів буде здійснюватися завантаження необхідного екземпляра функції. Цей механізм називається перевантаженням функцій. Одна з найважливіших властивостей поліморфізму – перевизначення стандартних функцій, при якій в залежності від типів даних у виразах викликається необхідний екземпляр операції. Перевизначення може виконуватися для наступних стандартних операцій: +, –, *, /, =, <, >, +=, –=, *=, /=, <<, >>, <<=, >>=, ==, !=, <=, >=, ++, ––, %, &, ^, !, ~, &=, ^=, |=, |, &&, ||, %=, [], (), new, delete Не можуть бути перевизначені операції: . , .*, ?:, ::, sizeof. Перевизначення операції може виконуватися з допомогою визначення операторної функції наступного формату: тип_результату operatorзнак_операції (список_параметрів) {оператори_тіла_операторної_функції} Тут тип_оператора визначає тип повертає мого значення при виконанні перевизначеної операції; в круглих дужках задається список типів параметрів, при наявності яких у аргументів звернення до операції до операцій з даним знаком буде виконуватися перевантаження (виклик) саме цього екземпляру операції. [2] Один з варіантів використання поліморфізму – віртуальні функції. Якщо при використанні віртуальної функції запит здійснюється з допомогою вказівника базового класу (або посилання), то С++ вибирає правильно перевизначену функцію у відповідному похідному класі, який зв’язаний з цим об’єктом. Іноді функція-елемент визначається в базовому класі як віртуальна, але перевизначена в похідному класі. Якщо така функція-елемент викликається через вказівник похідного класу, то використовується версія похідного класу. Це не поліморфна поведінка. Завдяки використанню поліморфних функцій та поліморфізму виклик функції-елемента може привести до різних дій, які залежать від типу об’єкту, який викликається. [5] Як вже було сказано, механізм керування доступом дозволяє виділяти загальнодоступні (public), захищені (protected) та власні (private) компоненти класів. Захищені компоненти доступні всередині класу та в похідних класах. Власні компоненти локалізовані в класі та недоступні ззовні. З допомогою загальнодоступних компонентів реалізується взаємодія класу з будь-якими частинами програми. Проте, є ще одна можливість розширити інтерфейс класу. Це забезпечують дружні функції. За визначенням, дружньою функцією класу є функція, яка не будучи його компонентом, має доступ до його захищених та власних компонентів. Функція не може стати другом класу «без його згоди». Для отримання прав друга функція повинна бути описана в тілі класу із специфікатором friend. Саме при наявності такого опису клас дає функції права доступу до захищених та власних компонентів. Приклад роботи класу з дружньою функцією. #include <conio.h>//для консольних функцій у текстовому режимі //клас «символ у заданій позиції екрану» classcharlocus { intx, y; //координати місця символу на екрані charcc; //прототип дружньої функції для заміни символу friend void friend_put (charlocus*, char); public: charlocus (int xi, int yi, char ci)//конструктор { x = xi; y = yi; cc = ci; } voiddisplay (void) //вивести символ на екран { gotoxy(x, y); putch(cc); } } //дружня функція заміни символа в конкретному об’єкті void friend_put(charlocus *p, char c) { p -> cc = c; } void main() { charlocus D(20, 4, ‘d’);//створити об’єкт charlocusS(10, 10, ‘s’); //створити об’єкт clrscr(); //очистити екран D.display(); getch(); S.display(); getch(); friend_put(&D, ‘*’); D.display(); getch(); friend_put(&S, ‘#’); S.display(); getch(); } Програма послідовно виводить на екран в (в позицію 20, 4), sв позицію (10, 10), * (в позицію 20, 4), # (в позицію 10, 10). Також один клас може бути дружнім для іншого. Це означає, що всі компонентні функції класу є дружніми для іншого класу. Дружній клас повинен бути визначеним за тілом класу, який «надає дружбу». Наприклад, так: class X2 {friend class1; ...}; class X1 {... void f1(...); void f2(...); ... } }; В даному випадку функції f1 та f2 із класу x1 є друзями класу x2, хоча вони описуються без специфікатора friend. Усі компоненти класу доступні у дружньому класі. Дружній клас може бути визначеним перед тим, як описаний як дружній. [3] Для розв’язання деяких задач дуже зручно використовувати параметризовані класи на основі шаблонів. Шаблон – це спеціальний опис родової (параметризованої) функції або класу, у яких інформація об використаних в реалізації типах даних спеціально остається незаданою. Типи використаних даних передаються через параметри шаблону. Апарат шаблонів дозволяє одну й ту саму функцію або клас використовувати з різними типами даних без необхідності програмувати заново кожну версію функції або класу. Компілятор автоматично породжує стільки різних версій функцій або класів, скільки потрібно для опрацювання кожного із знов використаних типів. [2] 1.5 Розробка класів з використанням технології візуального програмування Розглянемо технологію розробки класів в системі програмування BorlandC++ Builder. Це – одна з сучасних систем, яка має розвинені можливості та підтримую концепцію об’єктно-орієнтованого та візуального програмування. В системі BorlandC++ Builder бібліотекою класів є бібліотека візуальних компонентів (VCL). Особливості бібліотеки полягають у тому, що компонентами, які використовуються в програмі, можна управляти за допомогою методів, властивостей та об’єктів. Існує три елемента керування об’єктами: властивості, методи та події. Властивості об’єкта визначають його характеристики та поведінку. Наприклад, для об’єкта форма (вікно) властивість Caption визначаю назву в виді тексту, яка буде відображатися в верхній частині вікна, Color задає колір вікна, Width – його ширину і т.д. Методи, на відміну від властивостей, які представляють собою змінні або об’єкти, методи представляють собою функції-члени класу (об’єкту), які можна викликати ззовні для керування об’єктом. Наприклад, щоб вікно стало невидимим в процесі робот програми, можна викликати наступний метод: Form1 –> Hide(); Щоб вікно стало знову видимим, треба викликати інший метод: Form1 –> Show(); і т.д. Третій елемент керування об’єктом – події. Для кожного об’єкта із VCLіснує свій перелік подій, для яких можна замінити стандартну реакцію програми. Позначимо деякі особливості використання VCLв BorlandC++ Builder. Сама бібліотека VCLнаписана на Об’єктному Паскалі. Це обумовлює ряд обмежень на її використання, тому що Об’єктний Паскаль уступає в потужності реалізації принципів ООП на мові С++. VCLне допускає використання перевантажений функцій; використані функції-члени класу не мають аргументів за замовченням; класи із VCLне підтримують множинне успадкування. Вказані особливості ведуть до зниження гнучкості використання VCL. Однак переваги концепції візуального програмування роблять ці недоліки бібліотеки VCL малозначними. [2] 2. Розробка класу classProgressBar 2.1 Постановка задачі та обрані методи її розв’язку В цій курсовій роботі розроблено клас classProgressBar, на основі якого побудовано ієрархію класів, яка дозволяє створювати об’єкти типу «смужка прогресу». Можливо створити смужку прогресу чотирьох форм – горизонтальну (похідний клас horBar), вертикальну (похідний клас vertBar), смужку у формі кола (похідний клас roundBar) та смужку у формі кільця (похідний клас ringBar). Базові класи classProgressBar та fontмістять методи та дані, загальні для усіх успадкованих класів. Як вже позначалося, пара базових класів потрібна для демонстрації множинного успадкування. Взагалі структуру базових класів з їхніми методами та даними можна представити наступним чином: Мал. 2. Структура базових класів Пунктирними стрілками показано, що немає різниці, якому з базових класів належить метод. В загальному випадку можна всі методи помістити в один базовий клас (classProgressBar) і вже від нього успадковувати всі інші класи. Але в цьому випадку втратиться можливість продемонструвати множинне успадкування. Теж саме можна сказати щодо даних базових класів. Таким чином, кожен з успадкованих класів успадковує методи для зміни кольору тексту, смужки та фону (classProgressBar) та зміни шрифту тексту (font). В успадкованих класах в залежності від задачі описані «індивідуальні» методи. Взагалі кожен з успадкованих класів має конструктор для ініціалізації об’єкту, а також методи для встановлення розміру віконця, встановлення необхідних кольорових характеристик, шрифту, та функцію, яка виводить об’єкт на екран. 2.2 Реалізовані концепції ООП Реалізація програми проводилася з використанням основних концепцій ООП. В даному випадку дуже зручно використати саме концепції ООП, оскільки при роботі програми будується ієрархія відповідних класів (успадкування), використовуються однойменні функції (поліморфізм), а ініціалізація об’єктів реалізуються через конструктори (інкапсуляція). Використання цих концепцій дозволило по-перше, чітко визначити межі між об’єктами (за допомогою використання класів), по-друге, це позволило скоротити програмний код за рахунок використання в успадкованих класах функцій, описаних в базових класах. Нарешті, по-третє, використання конструкторів в класах дозволило автоматизувати процес ініціалізації об’єктів. На основі базових класів classProgressBar та font була побудована ієрархія класів з використанням множинного та поодинокого успадкування. Множинне успадкування продемонстроване на успадкуванні класів horBar, vertBar та roundBar. Одиночне успадкування продемонстровано на успадкуванні класу ringBar. Динамічний поліморфізм реалізується з використанням віртуальної функції-метода my_colors, описаної в класі classProgressBar. Таким чином, можна перевантажити цю функцію в похідних від classProgressBarкласах. Статичний поліморфізм використовується в класах roundBar та ringBar стосовно методів size. Тобто, методи size успадковуються класом ringBarта можуть бути перевантажені в ньому. Схема успадкування показана на малюнку 2.
Мал. 3. Схема успадкування 2.3 Опис класів 2.3.1 Базовий клас classProgresBar Базовий клас classProgressBar містить віртуальну функцію-метод my_colors, який дозволяє користувачеві вибрати колір шрифту, колір фону та колір смужки. Колір заповнення смужки поміщується в змінну fillc (fillcolor), яка має статус доступу protected. Тобто, ця змінна успадковується та її значення може змінюватися в похідних класах. Колір фону поміщується в змінну backc (backcolor), яка має статус доступу public. Значення цієї змінної можна буде змінити з тіла основної процедури. Віртуальна функція my_colorsвизначена з метою її можливого перевизначення в одному з успадкованих класів, тобто таким чином продемонстровано механізм віртуальних функцій. Перевизначення кольору тексту реалізується з допомогою функції setcolor модуля graphics.h, а перевизначення кольору фону реалізується з допомогою функції setbkcolor того ж самого модуля. Така консистенція базового класу classProgressBar була обрана тому що саме параметри, які визначають колір, є загальними для усіх видів ProgressBar, тобто ці параметри будуть раціонально успадковуватися в кожний з похідних від classProgressBar класів з можливістю зміни деяких з них (backc). 2.3.2 Базовий клас font Також створено базовий клас font, метод my_font якого дозволяє користувачеві встановлювати необхідний шрифт написів. Мотив створення цього класу – такий самий, як в класі classProgressBar. Тобто шрифт є загальним параметром для кожного з можливих ProgressBar. Перевизначення шрифту реалізується за допомогою функції settextstyle модуля graphics.h. Перший аргумент показує номер обраного шрифту, другий – направлення тексту, третій – розмір букв. Оскільки нас цікавить саме шрифт тексту, то два других параметри прирівнюємо до 0. 2.3.3 Похідні класи horBar, vertBar, roundBar та ringBar Клас horBar є похідним від класів font та classProgressBar. Похідний клас horBar надає можливість створювати горизонтальну смужку прогресу. Цей клас містить конструктор, за допомогою якого користувач може ввести необхідний відсоток прогресу (від 0 до 100) відповідно до обсягу виконаної роботи. Значення цього відсотку буде міститься у змінній p, яка має статус доступу protected. Це зроблено для того, щоб на основі класу horBar можна було створювати похідні класи, і при цьому відсоток виконаної роботи зберігається. Треба наголосити, що всі смужки прогресу в даній курсовій роботі представляють собою окремі об’єкти без прив’язки до конкретної дії. Тобто користувач сам обирає скільки відсотків прогресу пройдено після певної дії. Метод sizeцього класу задає лінійні параметри віконця смужки прогресу. Аргументами цього методу є координати верхнього лівого та нижнього правого кутів віконця. Для демонстрації динамічного поліморфізму в класі horBar створено конструктор копіювання. Тобто, при тестуванні цього класу спочатку буде створюватися певний об’єкт за допомогою основного конструктора, далі буде створена копія цього об’єкту за допомогою конструктора копіювання і методи класу horBar будуть приміняться до об’єкта-копії. Оскільки при створені об’єктів таким чином використовується динамічна пам’ять, то при закінченні роботи об’єктів використовуються однойменний деструктор для визволення використаного об’єму динамічної пам’яті. Метод show класу horBar виконує дві функції: по-перше, цей метод надає можливість користувачеві міняти положення віконця смужки прогресу на екрані (можна переміщувати віконце вправо – d, вліво – a, вниз – s, вгору - w). Переміщення припиняється після натискання кнопки r. По-друге, вже після вибору місця положення віконця на екрані, метод show заповнює відповідну частину смужки прогресу певним кольором. Структура методу showє приблизно однаковою для всіх класах. В класі horBarперевантажена віртуальна функція my_colors. Тобто перевизначити кольори можна також із класу horBar. Взагалі, використання віртуальної функції в даному випадку не є раціональним, оскільки метод my_colors і так буде успадковуватися в клас horBar. Використання віртуальної функції тут є прикладом використання концепції динамічного поліморфізму. Підчас заповнення смужки прогресу у верхній частині екрану можна побачити відсоток заповнення. На відмітках 25%, 50%, 75% та 100% внутрішній динамік комп’ютера подає звуковий сигнал частотою 500 Гц тривалістю 0,3 сек для зручнішої орієнтації в обсязі виконаної роботи. Аналогічний принцип дії має клас vertBar, на основі якого можна створювати вертикальні смужки прогресу. Цей клас також успадковуються від базових класів classProgressBar та font. Конструктор, деструктор та методи size, show класу vertBar виконують такі ж самі дії, що і в класі horBar, тільки у відповідних координатах (тобто, щоб смужка прогресу росла вгору). Також в класі vertBar визначена дружня функція my_size, яка може відігравати роль методу size, тобто визначення границь віконця. Функція my_size описана поза класу vertBar (як і треба для дружньої функції). Використання дружньої функції є раціональним, якщо вона використовується в декількох класах і в основній програмі. Тобто, це дозволяє скоротити програмний код. В нашому випадку використання дружньої функції не є раціональним, тому що вона використовується лише для класу vertBar. Ще одною різницею між класами horBar та vertBar є те, що в останньому відсутній конструктор копіювання, і об’єкт, створений на основі цього класу ініциалізується за допомогою базового конструктора. Класів ringBar (смужка прогресу в вигляді кільця) є похідним від класу roundBar (смужка прогресу у виді кругу), який в свою чергу успадковується від базових класів classProgressBar та font. Успадкування класів horBar, vertBar та roundBar від базових класів classProgressBar та font демонструє концепцію множинного успадкування. В цій курсовій роботі використання множинного успадкування є чисто демонстративним і не є раціональним, тому що один-єдиний метод класу font (my_font) можна було б помістити в клас classProgressBar. Використання множинного успадкування говорить о том, що методи та дані базових класів є загальними для усіх похідних (успадкованих) класів. Дійсно, вибір кольорів шрифту, фону, смужки прогресу та шрифту є загальними діями для усіх похідних класів. Концепція поодинокого успадкування демонструється на успадкуванні класу ringBar від класу roundBar. Клас roundBar має конструктор, деструктор, методи size(intx0, inty0), size (intrad) та show, які виконують відповідні аналогічні дії як в класах horBar та vertBar. При об’яві класу-родителя класу ringBar вказано специфікатор virtual в разі використання вказівника на базовий клас roundBar (базовий для ringBar). Клас ringBar має свій метод show, але успадковує методи size (обидва) класу roundBar. Наявність двох функцій-методів в класі roundBar демонструє статичний поліморфізм. Тобто, ідентифікатори у функцій одинакові, а кількість змінних та відповідні дії, які виконуються функціями, – різні. Також в межах класу ringBar перевантажено стандартну функцію “+”. Це перевантаження передбачає збільшення радіуса віконця першого об’єкту при використанні її як суми двох об’єктів класу ringBar. Тобто, таким чином радіус першого об’єкту буде дорівнювати сумі радіусів доданих об’єктів. Заповнення круга відповідним кольором в класі roundBar відбувається за допомогою функції pieslice модуля graphics.h. Ця функція дозволяє намалювати зафарбований сектор круга. Аналогічно організовано клас ringBar, тільки всередині круга розташований ще один зафарбований круг меншого радіуса. 2.4 Методи тестування програми Розглянемо тіло основної процедури та методи тестування програми. На початку йде ініціалізація графічного режиму (в режимі VGA 640x480x16). Далі користувачеві надається можливість вибрати один з чотирьох PrograssBar. Після вибору на екрані з’являється віконце смужки прогресу. З цього моменту користувач може двигати її в різні сторони екрана, користуючись кнопками “a”,”s”,”d”,”w”. Закінчення руху позначається натисканням кнопки “r”. Недоліком такої організації руху є те, що щоб перемістити об’єкт треба 2 рази натиснути на відповідну кнопку. Це трапилося внаслідок подвійного використання функції getch() – запиту символу з клавіатури. Перший раз йде перевірка, чи є нажата кнопка “r”, а другий раз ідентифікує саму нажату кнопку та виконує відповідні дії. Нехай вибрано варіант 1 – горизонтальна смужка прогресу. Тоді йде ініціалізація самого об’єкту, використовуючи основний конструктор horBar. Далі йде створення та ініціалізація такого ж самого об’єкту за допомогою конструктора копіювання та використання методів my_color та my_font базових класів. За допомогою метода sizeвибирається необхідний розмір віконця смужки прогресу. Далі, використовуючи метод show,смужка прогресу починає свій рух. Після зупинки об’єкт «горизонтальна смужка прогресу» знищується за допомогою деструктора. Аналогічно тестується вертикальна смужка прогресу – варіант 2 (клас vertBar), тільки конструктор копіюванняне використовується. Інший спосіб ініціалізації та користування об’єктів описаний при виклику смужки прогресу в вигляді круга (roundBar). Тут створюється спочатку сам об’єкт, потім створюється вказівник на нього за тим же типом (roundBar). Далі можна використовувати методи класу, звертаючись до них через вказівник. Тобто, тут використовується динамічна пам’ять для роботи з класом, його методами та даними. Тестування класу ringBar проводилося як і для класів horBar та vertBar. В результаті отримали бажані результати. При створенні об’єктів horBar та vertBar на екрані з’являється кероване віконце (горизонтальне та вертикальне відповідно) смужки прогресу, і після натискання кнопки “r” йде рівномірне заповнення віконця смужкою відповідного кольору. Паралельно йде відлік виконаного обсягу роботи у відсотках в верхній частині екрану. При використанні об’єктів roundBar та ringBar на екрані з’являються відповідно керовані коло та кільце, і після натискання кнопки “r” йде рівномірне обертання радіуса з паралельним заповненням об’єктів певним кольором. Особливістю використання ringBar є те, що за рахунок різних частот (системна обумовленість) появи нового стану смужки прогресу та внутрішнього круга, іноді можна помітити внутрішню частину віконця (тобто, новий стан смужки прогресу вже є, а круга, який закриває внутрішню частину віконця, немає). Такий процес займає десяті долі секунди. 2.5 Результати виконання програми У відповідності до обраних варіантів ProgressBarприводимо результати виконання програми. 1. Горизонтальний Progress Bar 2. Вертикальний Progress Bar 3. Круговий Progress Bar 4. Кільцевий ProgressBar Текст програми з коментарями приведений в Додатку 1. 3. Висновки В ході виконання курсової роботи були отримані наступні результати. Розроблено клас classProgressBar, який призначений для базування на ньому ієрархії класів з метою створення об’єктів типу «смужка прогресу» різних форм. Розроблений клас включає два компоненти-дані та один віртуальний компонент-метод, серед яких один компонент-дане є захищеним, а всі інші – загальнодоступними. На основі розробленого класу classProgressBar побудована ієрархія класів horBar, vertBar, roundBar та ringBar. Результати тестування підтвердили працездатність і ефективність використання об'єктів, створюваних на основі розробленого класу. Розроблене програмне забезпечення функціонує під керуванням операційної системи MSDOS. 4. Література 1. Шилдт Г. Самоучитель С++. – С.-Пб.: БХВ-Петербург, 2003. 2. під редакцією О.Д. Хомоненка. Программирование на С++. – С.-Пб.: Корона-принт, 1999. 3. Подбельський В.В. Мова С++. – М.: Фінанси та статистика, 2003. 4. Лаптєв В.В. С++. Експрес-курс. – С.-Пб.: БХВ-Петербург, 2004. 5. Дейтел Х., Дейтел П. Як програмувати на С++. – М.: ЗАТ«Видавництво БІНОМ», 2003. 5. Додатки Додаток 1 Текст тестової програми з коментарями. #include <conio.h> #include <graphics.h> #include <dos.h> #include <stdio.h>//підключаємо необхідні бібліотеки //---------------------------------- class classProgressBar//клас classProgressBar { protected: int fill//захищена змінна fillc – колір заповнення public: //загальнодоступні дані та методи intbackc; //колір фону virtual void my_colors(int text, int back, int fillcolor); //прототип віртуальної функції my_colors }; //опис віртуальної функції заміни кольору void classProgressBar::my_colors(int text, int back, int fillcolor) { setcolor(text); //вибір кольору шрифту setbkcolor(back); //вибір кольору фону fillc = fillcolor; //запам’ятовуємо колір заповнення backc = back; //запам’ятовуємо колір фону } //----------------------------------------- classfont//другий базовий клас - font { public: void my_font(int font); //прототип метода my_font }; void font::my_font(int font) //описання методу – вибір шрифту { settextstyle(font, 0, 0); } //----------------------------------------- //клас «горизонтальна смужка» class horBar:public classProgressBar, public font { protected: int x1, y1, x2, y2, p; public: horBar(int p);//конструктор. р – обсяг виконаної роботи //прототип функції – вибір розміру void size(int xt, int yt, int xb, int yb); horBar(horBar &h);//прототип конструктора копіювання voidshow();//прототип метода show //перевантаження віртуальної функції void my_colors(int text, int back, int fillcolor) { setcolor(text); //вибираємо колір тексту setbkcolor(back); //вибираємо колір фону fillc = fillcolor; backc = back; //запам’ятовуємо кольори }; ~horBar(); //прототип деструктора }; horBar::horBar(horBar &h) //описуємо конструктор копіювання { p = h.p; } horBar::~horBar(){} //описуємо деструктор horBar::horBar(intper)//описуємо основний конструктор { p = per;//р – обсяг виконаної роботи } //метод sizeдля вибору параметрів віконця void horBar::size(int xt, int yt, int xb, int yb) { x1 = xt; y1 = yt; x2 = xb; y2 = yb; } //метод show – показуємо об’єкт void horBar::show() { float del = (x2 - x1) / 100;//шаг, з яким буде мінятися //смужка intdefc = 5, step = 20; //колір рамки віконця та шаг //переміщення charx = 40, y = 1; //координати виводу відсотків setcolor(defc); //встановлюємо колір рамки //віконця – defaultcolor rectangle(x1, y1, x2, y2); //малюємо рамку while (getch() != 'r')//організовуємо рух { switch(getch()) { case 'd': setcolor(backc); //малюємо об’єкт кольором фону //на його старому місці (стираємо) rectangle (x1, y1, x2, y2); setcolor(defc); x1 = x1 + step; x2 = x2 + step; rectangle (x1, y1, x2, y2); //малюємо новий об’єкт //на новому місці break; case 'a': setcolor(backc); rectangle (x1, y1, x2, y2); setcolor(defc); x1 = x1 - step; x2 = x2 - step; rectangle (x1, y1, x2, y2); break; case 's': setcolor(backc); rectangle (x1, y1, x2, y2); setcolor(defc); y1 = y1 + step; y2 = y2 + step; rectangle (x1, y1, x2, y2); break; case 'w': setcolor(backc); rectangle (x1, y1, x2, y2); setcolor(defc); y1 = y1 - step; y2 = y2 - step; rectangle (x1, y1, x2, y2); break; }; } setcolor(fillc); for (int w = 1; w < p + 1; w++) { if ((w == 25)||(w == 50)||(w == 75)||(w == 100)) { sound(550); delay(300); nosound();//організовуємо звук } if (w < p) { gotoxy (x, y); printf ("%i%", w + 1); line(x1 + 1, y1 + 1, x1 + 1, y2 - 1); delay(100); x1 = x1 + del; } } getch(); } //----------------------------------------- class vertBar: public classProgressBar, public font { protected: int x1, y1, x2, y2, p; friend void my_size(vertBar *t, int xt, int yt, int xb, int yb); public: vertBar(int p); void size(int xt, int yt, int xb, int yb); void show(); ~vertBar(); }; vertBar::~vertBar(){} vertBar::vertBar(int per) { p = per; } void vertBar::size(int xt, int yt, int xb, int yb) { x1 = xt; y1 = yt; x2 = xb; y2 = yb; } void vertBar::show() { float del = (y2 - y1) / 100; int defc = 5; char x = 40, y = 1, step = 20; setcolor(defc); rectangle(x1, y1 - 1, x2, y2); while (getch() != 'r') { switch(getch()) { case 'd': setcolor(backc); rectangle (x1, y1 - 1, x2, y2); setcolor(defc); x1 = x1 + step; x2 = x2 + step; rectangle (x1, y1 - 1, x2, y2); break; case 'a': setcolor(backc); rectangle (x1, y1 - 1, x2, y2); setcolor(defc); x1 = x1 - step; x2 = x2 - step; rectangle (x1, y1 - 1, x2, y2); break; case 's': setcolor(backc); rectangle (x1, y1 - 1, x2, y2); setcolor(defc); y1 = y1 + step; y2 = y2 + step; rectangle (x1, y1 - 1, x2, y2); break; case 'w': setcolor(backc); rectangle (x1, y1 - 1, x2, y2); setcolor(defc); y1 = y1 - step; y2 = y2 - step; rectangle (x1, y1 - 1, x2, y2); break; default: putch('q'); }; } setcolor(fillc); for (int w = 1; w < p + 2; w++) { if ((w == 26)||(w == 51)||(w == 76)||(w == 101)) { sound(550); delay(300); nosound(); } if (w < p + 1) { gotoxy(x, y); printf("%i%", w); line(x1 + 1, y2 - 1, x2 - 1, y2 - 1); delay(100); y2 = y2 - del; } } getch(); } //----------------------------------------- void my_size(vertBar *t, int xt, int yt, int xb, int yb) { t -> x1 = xt; t -> y1 = yt; t -> x2 = xb; t -> y2 = yb; } //----------------------------------------- class roundBar: public classProgressBar, public font { protected: int x0, y0, r, p, defc; public: void size(int x, int y); void size(int rad); void show(); roundBar(int per); ~roundBar(); }; roundBar::~roundBar(){} void roundBar::size(int x, int y) { x0 = x; y0 = y; } void roundBar::size(int rad) { r = rad; } roundBar::roundBar(int per) { p = per; } void roundBar::show() { int x = 40, y = 1, step = 20; setcolor(5); circle(x0, y0, r); backc = 0; while (getch() != 'r') { switch (getch()) { case 'd': setcolor(backc); circle(x0, y0, r); x0 = x0 + step; setcolor(5); circle (x0, y0, r); break; case 'a': setcolor(backc); circle(x0, y0, r); x0 = x0 - step; setcolor(5); circle (x0, y0, r); break; case 's': setcolor(backc); circle(x0, y0, r); y0 = y0 + step; setcolor(5); circle (x0, y0, r); break; case 'w': setcolor(backc); circle(x0, y0, r); y0 = y0 - step; setcolor(5); circle (x0, y0, r); break; } } for (int j = 0; j < p + 1; j++) { if ((j == 26) || (j == 51) || (j == 76) || (j == 100)) { sound(550); delay(200); nosound(); } gotoxy (x, y); printf ("%i%", j); pieslice(x0, y0, 0, j * 3.6, r); delay(300); } getch(); } //----------------------------------------- class ringBar: virtual public roundBar { public: ringBar(int per): roundBar(per) { p = per; }; void show(); void operator + (ringBar&); }; void ringBar::operator + (ringBar &c) { c.r = c.r + r; } void ringBar::show() { int x = 40, y = 1, step = 20; setcolor(5); circle(x0, y0, r); circle(x0, y0, r / 1.5); while (getch() != 'r') { switch (getch()) { case 'r': break; case 'd': setcolor(backc); circle(x0, y0, r); circle(x0, y0, r / 1.5); x0 = x0 + step; setcolor(5); circle(x0, y0, r); circle(x0, y0, r / 1.5); break; case 'a': setcolor(backc); circle(x0, y0, r); circle(x0, y0, r / 1.5); x0 = x0 - step; setcolor(5); circle (x0, y0, r); circle(x0, y0, r / 1.5); break; case 's': setcolor(backc); circle(x0, y0, r); circle(x0, y0, r / 1.5); y0 = y0 + step; setcolor(5); circle (x0, y0, r); circle(x0, y0, r / 1.5); break; case 'w': setcolor(backc); circle(x0, y0, r); circle(x0, y0, r / 1.5); y0 = y0 - step; setcolor(5); circle (x0, y0, r); circle(x0, y0, r / 1.5); break; } } for (int j = 0; j < p + 1; j++) { if ((j == 26) || (j == 51) || (j == 76) || (j == 100)) { sound(550); delay(200); nosound(); } gotoxy (x, y); printf ("%i%", j); pieslice(x0, y0, 0, j * 3.6, r); setfillstyle(0, 0); fillellipse(x0, y0, r / 1.5, r / 1.5); setfillstyle(1, 1); delay(300); } getch(); } //----------------------------------------- void main() { clrscr(); int gd = VGA, gm = 2; initgraph(&gd, &gm, "...\\bgi"); //------------------------------------- printf("Progress Bars:" "\n1 - Horizontal;\n2 - Vertical;" "\n3 - Round; \n4 - Ring."); switch(getch()) { case '1': horBar a(100); horBar a1 = a; a1.my_colors(1, 0 ,2); a1.my_font(4); a1.size(140, 140, 240, 170); a1.show(); a1.horBar::~horBar(); break; //---------------------- case '2': vertBar b = vertBar(100); b.my_colors(1, 0 ,2); b.my_font(4); my_size(&b, 140, 140, 190, 240); b.show(); b.vertBar::~vertBar(); break; //----------------------- case '3': roundBar c(100); roundBar *k; k = &c; k -> size(150, 150); k -> size(100); (*k).show(); c.roundBar::~roundBar(); break; //----------------------- case '4': ringBar d(5); d.size(150, 150); d.size(100); d.show(); break; default: gotoxy (1, 6); printf ("Choose 1, 2, 3, or 4 !!!"); getch(); } //------------------------------------- closegraph(); } |