
- •Міністерство надзвичайних ситуацій України Львівський державний університет безпеки життєдіяльності Юрій грицюк, Тарас рак
- •Навчальний посібник
- •Потреба використання об'єктно-орієнтованого програмування
- •Поняття про об’єктно-орієнтований підхід до розроблення складних програм
- •Основні компоненти об’єктно-орієнтованої мови програмування
- •Поняття про універсальну мову моделювання
- •Базові поняття класу
- •Код програми 2.1. Демонстрація механізму оголошення класу та його застосування
- •Поняття про конструктори і деструктори
- •Особливості реалізації механізму доступу до членів класу
- •Класи і структури - споріднені типи
- •Об'єднання та класи - споріднені типи
- •Поняття про вбудовані функції
- •Inline int myClass::Put() return c;
- •Особливості організації масивів об'єктів
- •Особливості використання покажчиків на об'єкти
- •Поняття про функції-"друзі" класу
- •Код програми 3.1. Демонстрація механізму використання "дружньої" функції для доступу до закритих членів класу
- •Код програми 3.2. Демонстрація механізму використання "дружньої" функції для перевірки статусу кожного об'єкта
- •Void Run(); //Таймер відліку часу
- •Void timerClass::Run()
- •Int mainO
- •Особливості механізму динамічної ініціалізації конструктора
- •Int s; public:
- •Void Run(); //Таймер відліку часу
- •Void timerClass::Run()
- •Int mainO
- •Особливості механізму присвоєння об'єктів
- •Int а, ь; public:
- •Int mainO
- •Особливості механізму передачі об'єктів функціям
- •Void Fun(myClassobj)
- •Int mainO
- •Конструктори, деструктори і передача об'єктів
- •Void Get(myClass obj)
- •Int mainO
- •Потенційні проблеми, які виникають при передачі об'єктів
- •Int *р; public:
- •Void Get(myClass &obj) // Передача об'єкта за посиланням
- •Int mainO
- •Особливості механізму повернення об'єктів функціями
- •Void Set(char*s) {strcpy(str, s);}
- •Void Show() {cout «"Рядок:" « str« endl;}
- •Int mainO
- •Int mainO
- •Механізми створення та використання конструктора копії
- •Використання конструктора копії для ініціалізації одного об'єкта іншим
- •Int mainO
- •Механізм використання конструктора копії для передачі об'єкта функції
- •Int mainO
- •Механізм використання конструктора копії при поверненні функцією об'єкта
- •Int mainO
- •3.7.4. Конструктори копії та їх альтернативи
- •Поняття про ключове слово this
- •Void Fun() {...};
- •Int mainO
- •Механізми перевизначення операторів з використанням функцій-членів класу
- •Int х, у, z; //Тривимірні координати
- •Int mainO
- •Intх,у,z; //Тривимірні координати
- •Void Show(char*s);
- •Int mainO
- •Int х, у, z; //Тривимірні координати
- •Int mainO
- •Особливості реалізації механізму перевизначення операторів
- •Механізми иеревизначення операторів з використанням функцій-не членів класу
- •Використання функцій-"друзів" класу для перевизначення бінарних операторів
- •Void Show(char*s);
- •Int mainO
- •Int mainO
- •Використання функцій-"друзів" класу для перевизначення унарних операторів
- •Int mainO
- •Особливості реалізації оператора присвоєння
- •Int mainO
- •Int mainO
- •Механізми перевизначення оператора індексації елементів масиву "[]"
- •Int mainO
- •Int aMas[size]; public:
- •Int mainO
- •Int aMas[size]; public:
- •Int mainO
- •Механізми перевизначення оператора виклику функцій "()"
- •Int mainO
- •Механізми перевизначення рядкових операторів
- •Конкатенація та присвоєння класу рядків з рядками класу
- •Void Show(char*s) {cout« s « string « endl;}
- •Конкатенація та присвоєння класу рядків з рядками, що закінчуються нульовим символом
- •Void Show(char*s) {cout« s « string « endl;}
- •Void Show(char*s) {cout« s « string « endl;}
- •Int mainO
- •Поняття про успадкування в класах
- •Int kolesa; // Кількість коліс int pasagyr; // Кількість пасажирів public:
- •Int mistkist; // Вантажомісткість у м куб. Public:
- •Int kolesa; // Кількість коліс int pasagyr; // Кількість пасажирів public:
- •Int mainO
- •Використання специфікатора доступу protected для надання членам класу статусу захищеності
- •Int mainO
- •Int mainO
- •Int d; // Захищений public:
- •Int mainO
- •Protected-членом класу derived, що робить його недоступним за його межами. */
- •Void showX() {cout« х « endl;}
- •Void showY() {cout« у « endl;}
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Успадкування віртуальних функцій
- •Void Show() {cout« Суг("Другий похідний клас.") « endl;}
- •Virtual void Show() {cout« Суг("Базовий клас.") « endl;}
- •Void Show() {cout« Суг("Перший похідний клас. ")« endl;}
- •Int mainO
- •Virtual void ShowO {cout« Суг("Базовий клас.") « endl;}
- •Void Show() {cout« Суг("Перший похідний клас. ")« endl;}
- •Int mainO
- •Void Show()
- •Void Show()
- •Int mainO
- •Void Show()
- •Void Show()
- •Int mainO
- •Void swapAb(aType &а, аТуре &b)
- •Int mainO
- •Приклад створення узагальненого класу для організації безпечного масиву
- •Int mainO
- •Використання в узагальнених класах аргументів, що не є узагальненими типами
- •Використання в шаблонних класах аргументів за замовчуванням
- •Int mainO
- •Механізм реалізації безпосередньо заданої спеціалізації класів
- •Int mainO
- •Основні особливості оброблення виняткових ситуацій
- •Системні засоби оброблення винятків
- •Xtest(1);
- •Xtest(2);
- •Перехоплення винятків класового типу
- •Використання декількох catch-наетанов
- •Варіанти оброблення винятків
- •Перехоплення всіх винятків
- •Накладання обмежень на тип винятків, які генеруються функціями
- •Int mainO
- •Xhandler(o); // Спробуйте також передати функції XhandlerO аргументи 1 і 2.
- •Void Xhandler(int test) throw 0
- •Повторне генерування винятку
- •Int mainO
- •Int mainO
- •Механізми перевизначення операторів new і delete
- •Void *р;
- •Void *p;
- •Int mainO
- •Класи потоків
- •Особливості механізмів перевизначення операторів введення-виведення даних
- •Створення перевюначених операторів виведення даних
- •Int mainO
- •Використання функцій-"друзів" класу для перевюначення операторів виведення даних
- •Int х, у, z; //Тривимірні координати (тепер це private-члени) public:
- •Int mainO
- •Створення перевюначених операторів введення даних
- •Istream &operator»(istream &stream, kooClass &obj)
- •Cout«"Введіть координати X, у і z:
- •Stream » obj.X » obj.Y » obj.Z;
- •Istream &operator»(istream &stream, objectType &obj)
- •// Код операторної функції введення даних
- •Class kooClass {// Оголошення класового типу int х, у, z; // Тривимірні координати
- •Istream &operator»(istream &stream, kooClass &obj)
- •Int mainO
- •Void unsetf(fmtflags flags),
- •Void showflags(ios::fmtflags f); // Відображення поточного стану опцій
- •Int mainO
- •Ios::fmtflags f; // Оголошення параметру для поточного стану опцій
- •Int mainO
- •Створення власних маніиуляторних функцій
- •Організація файлового введення-виведення даних
- •Відкриття та закриття файлу
- •Зчитування та запис текстових файлів
- •Ifstream in(argv[1], ios::in | ios::binary); if(!in){
- •In.CloseO; getchO; return 0;
- •Int mainO
- •Зчитування та записування у файл блоків даних
- •Int mainO
- •Ifstream inftest", ios::in | ios::binary); if(!in){
- •Використання функції eof() для виявлення кінця файлу
- •If(!in.Eof()) cout« ch;
- •In.CloseO; getchO; return 0;
- •Int main(int arge, char *argv[])
- •Ifstream f1(argv[1], ios::in | ios::binary); if(!f1) {
- •Ifstream f2(argv[2], ios::in | ios::binary);
- •Int main(int arge, char *argv[])
- •Ifstream in(argv[1], ios::in | ios::binary); if(!in){
- •In.Seekg(atoi(argv[2]), ios::beg); while(in.Get(ch)) cout« ch; getchO; return 0;
- •Int х, у, z; // Тривимірні координати; вони тепер закриті public:
- •Int mainO
- •Virtual void Fun() {}; // Робимо клас Base поліморфним
- •Int mainO
- •Virtual void FunO {cout«"у класі Base"« endl;}
- •Int mainO
- •Virtual void FunO {}
- •Void derivedOnlyO {cout«"Це об'єкт класу Derived"« endl;}
- •Int mainO
- •Void Fun(const int *р)
- •Int mainO
- •Namespace ns { int d;
- •Застосування настанови using
- •Int Comp(const void *а, const void *b);
- •Int mainO
- •Int Comp(const void *a, const void *b)
- •Int mainO
- •Int Fun10 const; // const-функція-член
- •Int PutO const; return c; // Все гаразд
- •Int mainO
- •0Bj.Set(1900); cout « Obj.PutO;
- •Void setJ(int х) const // Наступна функція не відкомпілюється.
- •Int а; public:
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int myClass::*dp; // Покажчик на int-члена класу void (myClass::*fp)(int X); // Покажчик на функцію-члена
- •Int mainO
- •Механізми роботи з векторами
- •Int mainO
- •1 234 5 678 9 10 11 12 13141516 17 1819 Вміст подвоєно:
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Символи н
- •Символів представляють голосні звуки.
- •Int mainO
- •Int mainO
- •Int mainO
- •Void getaLine(string& inStr); // Отримання рядка тексту char getaCharO; //Отримання символу
- •Int aptNumber; // Номер кімнати мешканця
- •Void DisplayO; // Виведення переліку мешканців
- •Int aptNo; float rent[12]; public:
- •Void setRent(int, float); // Запис плати за місяць
- •Void insertRent(int, int, float); void DisplayO;
- •Int month, day; string category, payee; float amount; expense() {}
- •Int mainO
- •Void rentRecord::insertRent(int aptNo, int month, float amount)
- •SetPtrsRr.Insert(ptrRow); // Занести рядок вектор
- •If( setPtrsRr.Empty())
- •Else // Інакше
- •Int month, day; string category, payee; float amount;
- •«" 'Є' для запису витрат:";
- •Навчальний посібник
Void getaLine(string& inStr); // Отримання рядка тексту char getaCharO; //Отримання символу
class tenant { // Мешканці
private:
string name; // Ім'я мешканця
Int aptNumber; // Номер кімнати мешканця
// Тут може бути будь-яка інша інформація про мешканця,
// наприклад, номер телефону і т.ін.
public:
tenant(string n, int aNo);
~tenant();
int getAptNumber(); // Потрібно для використання в множині friend bool operator < (const tenant&, const tenant&); friend bool operator == (const tenant&, const tenant&);
// Для операцій введення/виведення
friend ostream& operator« (ostream&, const tenant&);
}; // <—> Кінець оголошення класу tenant // Функціональний об'єкт для порівняння імен мешканців class compareTenants {
public:
bool operator 0 (tenant*, tenant*) const;
};
// >—> Клас tenantList class tenantList { private:
// Встановити покажчики на мешканців set<tenant*, compareTenants> setPtrsTens; set<tenant*, compareTenants>::iterator iter; public:
~tenantList(); // Оголошення деструктора (Видалення мешканців) void insertTenant(tenant*); // Внесення мешканця в перелік int getAptNo(string); // Повертає номер кімнати
Void DisplayO; // Виведення переліку мешканців
};
// <—> Кінець оголошення класу tenantList
class tenantlnputScreen { private:
tenantList* ptrTenantList; string tName; int aptNo; public:
tenantlnputScreen(tenantList* ptrTL): ptrTenantList(ptrTL)
{І* тут порожньо */} void getTenant();
}; // <—> Кінець класу tenantlnputScreen
// Один рядок таблиці прибутку: адреса і 12 місячних плат
class rentRow {
private:
Int aptNo; float rent[12]; public:
rentRow(int); // Оголошення конструктора з одним параметром
Void setRent(int, float); // Запис плати за місяць
float getSumOfRow(); // Сума платежів з одного рядка
// Потрібно для збереження в множині friend bool operator < (const rentRow&, const rentRow&); friend bool operator == (const rentRow&, const rentRow&); friend ostream& operator« (ostream&, const rentRow&); // Для виведення }; // <—> Кінець класу rentRow
// Функціональний об'єкт порівняння об'єктів rentRows
class compareRows {
public:
bool operator 0 (rentRow*, rentRow*) const;
};
class rentRecord { private:
// Множину покажчиків на об'єкти rentRow (по одному на мешканця) set<rentRow*, compareRows> setPtrsRR; set<rentRow*, compareRows>::iterator iter; public:
~rentRecord();
Void insertRent(int, int, float); void DisplayO;
float getSumOfRents(); // Сума усіх платежів }; // <—> Кінець класу rentRecord
class rentlnputScreen { private:
tenantList* ptrTenantList; rentRecord* ptrRentRecord; string renterName; float rentPaid; int month; int aptNo; public:
rentlnputScreen(tenantList* ptrTL rentRecord* ptrRR): ptrTenantList(ptrTL), ptrRentRecord(ptrRR)
{/*тут пусто*/}
void getRent(); // Орендна плата одного мешканця за один місяць }; // <—> Кінець класу rentlnputScreen
class expense { public:
Int month, day; string category, payee; float amount; expense() {}
expense(int m, int d, string c, string p, float a):
month(m), day(d), category(c), payee(p), amount(a)
{/* тут порожньо! */}
// Потрібно для зберігання в множині
friend bool operator < (const expense&, const expense&);
friend bool operator == (const expense&, const expense&);
// Потрібно для виведення
friend ostream& operator« (ostream&, const expense&);
}; // <—> Кінець класу expense // Функціональний об'єкт порівняння витрат class compareDates { public:
bool operator 0 (expense*, expense*) const;
};
// Функціональний об'єкт порівняння витрат
class compareCategories {
public:
bool operator 0 (expense*, expense*) const;
};
class expenseRecord { private:
// Вектор покажчиків на витрати vector<expense*> vectPtrsExpenses; vector<expense*>::iterator iter; public:
~expenseRecord(); void insertExp(expense*); void DisplayO;
float displaySummaryO; // Потрібно для річного звіту }; // <—> Кінець класу expenseRecord
class expenselnputScreen { private:
expenseRecord* ptrExpenseRecord; public:
expenselnputScreen(expenseRecord*); void getExpenseO;
}; // <—> Кінець класу expenselnputScreen
class annualReport { private:
rentRecord* ptrRR; expenseRecord* ptrER; float expenses, rents; public:
annualReport(rentRecord*, expenseRecord*); void DisplayO;
}; // <—> Кінець класу annualReport
class userlnterface { private:
tenantList* ptrTenantList; tenantlnputScreen* ptrTenantlnputScreen; rentRecord* ptrRentRecord; rentlnputScreen* ptrRentlnputScreen; expenseRecord* ptrExpenseRecord; expenselnputScreen* ptrExpenselnputScreen; annualReport* ptr AnnualReport; char ch; public:
userlnterfaceO;
~userlnterface();
void interactO;
}; // <—> Кінець класу userlnterfac
// <—> Кінець файлу landlord.h
Оголошення класів - це просто. Більшість оголошень зростають безпосередньо з класів, створених за допомогою узятих з описів варіантів використання іменників, і відображаються на діаграмі класів. Тільки імена з багатослівних потрібно зробити однослівними. Наприклад, ім'я "Перелік мешканців" (Tenant List) перетворюється в TenantList.
У заголовному файлі було додано ще декілька допоміжних класів. Згодом виявиться, що ми зберігаємо покажчики на об'єкти в різних типах контейнерів STL. Це означає, що ми повинні порівнювати об'єкти цих контейнерів так, як це описано в розд. 12 "Введення в стандартну бібліотеку шаблонів". Об'єктами порівняння насправді є класи compareTenants, compareRows, compareDates і compareCategories.
Описи атрибутів. Як уже було зазначено вище, багато атрибутів (методи) для кожного з класів є похідними з тих іменників, які самі не стали класами. Наприклад, name і aptNumber стали атрибутами класу tenant.
Інші атрибути можуть бути виведені з асоціацій в діаграмі класів. Асоціації можуть визначати ті атрибути, які є покажчиками або посиланнями на інші класи. Це пояснюється неможливістю асоціювати щось з чимось, що знаходиться невідомо де. Таким чином, у класі rentlnputScreen з'являються такі атрибути, як ptrTenantList і ptrRentRecord.
Складені значення (агрегати). Агрегатні зв'язки показані в трьох місцях на діаграмі класів. Зазвичай агрегати виявляють ті контейнери, які є атрибутами агрегатного класу (тобто "цілого" класу, що містить "частини").
Ні за описами варіантів використання, ні за діаграмами класів неможливо вгадати, якого роду контейнери повинні використовуватися для цих агрегатів. Вам як програмістам доведеться самим щоразу вибирати відповідний контейнер для кожного складеного значення - будь-то простий масив, контейнер STL або що-небудь ще. У програмі landlord ми зробили такий вибір:
клас tenantList містить STL-множину покажчиків на об'єкти класу tenant;
клас rentRecord містить множину покажчиків на об'єкти класу rentRow;
клас expenseRecord містить вектор покажчиків на об'єкти класу expense.
Для tenantList і rentRecord ми вибрали множини, оскільки основним параметром є швидкий доступ до даних. Для expenseRecord вибрано вектор, тому що нам важливо здійснювати швидке сортування і за датою, і за категоріями, а вектори дають змогу сортувати дані найефективніше.
У всіх агрегатах ми вважали за краще зберігати покажчики замість самих об'єктів, щоб уникнути зайвого копіювання даних у пам'яті. Зберігання самих об'єктів необхідно застосовувати в тих випадках, коли об'єктів мало і вони невеликі. Зазвичай, великої різниці в швидкості на прикладі якихось 12 екземплярів об'єкта ми не побачимо, але у принципі про ефективність методу зберігання даних необхідно замислюватися завжди.
Створення початкових *.срр файлів. У початкових файлах містяться тіла методів, які були оголошені в заголовному файлі. Написання коду програми цих
методів має починатися тільки на цьому етапі розроблення ПЗ і ні кроком раніше, тому що тільки зараз ми знаємо ім'я кожної функції, її призначення і навіть, можливо, можемо передбачити аргументи, що передаються їй.
Нарешті ми, так би мовити, відокремили зерна від полови: mainO зберігаємо в одному коротенькому файлі lordApp.cpp, а визначення функцій, оголошених у заголовному файлі, - в іншому. У секції mainO створюється об'єкт userlnterface і викликається метод interactO- Наведемо файл, у якому зберігається main().
Код програми 14.2. Демонстрація програми lordApp.cpp
// Файл, що постачається клієнту.
#include "landlord, h"