
- •Міністерство надзвичайних ситуацій України Львівський державний університет безпеки життєдіяльності Юрій грицюк, Тарас рак
- •Навчальний посібник
- •Потреба використання об'єктно-орієнтованого програмування
- •Поняття про об’єктно-орієнтований підхід до розроблення складних програм
- •Основні компоненти об’єктно-орієнтованої мови програмування
- •Поняття про універсальну мову моделювання
- •Базові поняття класу
- •Код програми 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 *р;
cout«"Виділення області пам'яті для об'єкта класу kooClass" « endl; р = malloc(size);
// Генерування винятку у разі невдалого виділення області пам'яті. if№){
bad_alloc ba; throw ba;
}
return p;
}
// Перевизначення оператора new для масиву об'єктів типу kooClass. void *kooClass::operator new[](size_t size)
{
Void *p;
cout«"Виділення області пам'яті для масиву kooClass-об'єктів" « endl; //Генерування винятку при невдачі, р = malloc(size); if№){
bad_alloc ba; throw ba;
}
return p;
}
// Перевизначення оператора delete для класу kooClass. void kooClass: operator delete(void *p)
{
cout«"Видалення об'єкта класу kooClass"« endl; free(p);
}
// Перевизначення оператора delete для масиву об'єктів типу kooClass. void kooClass: operator delete[](void *p)
{
cout«"Видалення масиву об'єктів типу kooClass" « endl; free(p);
}
// Відображення тривимірних координат х, у, z. void kooClass: :showB(char*s)
{
cout«"Координати об'єкта <"« s «">:";
cout«"\t\tx=" « x «", y="« у «", z=" « z « endl;
}
Int mainO
{
kooClass *p1,*p2; try {
p1 = new kooClass[3]; // Виділення області пам'яті для масиву р2 = new kooClass(5,6,7); // Виділення області пам'яті для об'єкта
}
catch(bad_alloc ba) {
cout«"Помилка під час виділення області пам'яті"« endl; return 1;
}
p1[1].showB("Ba30BHÜ клас:"); p2->showB("Ba30BHÜ клас:");
delete []р1; //Видалення масиву delete р2; // Видалення об'єкта getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати: Виділення області пам'яті для масиву kooClass-об'єктів.
Створення об'єкта 0,0,0 Створення об'єкта 0,0,0 Створення об'єкта 0,0,0
Виділення області пам'яті для об'єкта класу kooClass.
Створення об'єкта 5,6,7
0,0,0
5,6,7
Руйнування об'єкта Руйнування об'єкта Руйнування об'єкта
Видалення масиву об'єктів типу kooClass.
Руйнування об'єкта Видалення об'єкта класу kooClass.
Перші три повідомлення Створення об'єкта 0,0,0 видані конструктором класу kooClass (який не має параметрів) під час виділення області пам'яті для триелемен- тного масиву. Як уже зазначалося вище, під час виділення області пам'яті для масиву автоматично викликається конструктор кожного елемента. Повідомлення Створення об'єкта 5, 6, 7 видано конструктором класу kooClass (який приймає три аргументи) під час виділення області пам'яті для одного об'єкта. Перші три повідомлення Руйнування об'єкта видані деструктором внаслідок видалення триелементного масиву, оскільки при цьому автоматично викликався деструктор кожного елемента масиву. Останнє повідомлення Руйнування об'єкта видане під час видалення одного об'єкта класу kooClass. Важливо розуміти, що, коли оператори new і delete пере- визначені для конкретного класу, то внаслідок їх використання для даних інших типів будуть задіяні оригінальні версії операторів new і delete. Це означає, що при додаванні у функцію mainO наступного рядка буде виконано стандартну версію оператора new:
int *f = new int; // Використовується стандартна версія оператора new.
Вартоа нати! Оператори new і delete можна перевизначати глобально. Для цього достатньо оголосити їх операторні функції поза класами. У цьому випадку стандартні версії C++-операторів new і delete ігноруються взагалі, і в усіх запитах на виділення області пам'яті використовуються їх перевизначе- ні версії. Безумовно, якщо Ви при цьому визначите версію операторів new і delete для конкретного класу, то ці "класові" версії застосовуватимуться під час виділення області пам'яті (та її звільнення) для об'єктів цього класу. В усій же решті випадків використовуватимуться глобальні операторні функції.
Перевизначення nothrow-версїі оператора new. Можна також створити пе- ревизначені nothrow-версії операторів new і delete. Для цього використовуються такі механізми:
// Перевизначення nothrow-версії оператора new void ‘operator new(size_t size, const nothrow_t &n)
{
// Виділення області пам'яті. if(success) return pointer_to_memory; else return 0;
}
// Перевизначення nothrow-версії оператора new для масиву, void ‘operator new[](size_t size, const nothrow_t &n)
{
// Виділення області пам'яті. if(success) return pointer_to_memory; else return 0;
}
// Перевизначення nothrow-версії оператора delete, void operator delete(void *p, const nothrow_t &n)
{
// Звільнення пам'яті.
}
// Перевизначення nothrow-версії оператора delete для масиву, void operator delete[](void *p, const nothrow_t &n)
{
// Звільнення пам'яті.
}
Тип nothrow_t визначається в заголовку <new>. Параметр типу nothrow_t не використовується. Як вправу проекспериментуйте з throw-версіями операторів new і delete самостійно.
Розділ 9. ОРГАНІЗАЦІЯ С++-СИСТЕМИ ВВЕДЕННЯ-ВИВЕДЕННЯ ПОТОКОВОЇ ІНФОРМАЦІЇ
З самого початку висвітлення матеріалу у цьому навчальному посібнику використовувалася С++-система введення-виведення потокової інформації, але не наводилось детальних пояснень з механізму її реалізації. Оскільки С++-система введення-виведення побудована на ієрархії класів, то її теорію і деталі реалізації неможливо було засвоїти, не розглянувши спочатку механізм реалізації класів, успадкування в класах і оброблення винятків. Якраз після цього і настає момент для детального вивчення С++-засобів введення-виведення потокової інформації.
У цьому розділі будуть розглядатися засоби як консольного, так і файлового введення-виведення потокової інформації. Необхідно зразу ж відзначити, що С++- система введення-виведення - достатньо широка тема. Тому у поданому нижче матеріалі описано тільки найважливіші та часто вживані засоби організації С++- системи введення-виведення. Зокрема, спочатку дізнаємося про те, що розуміють під потоками у мові програмування С++, про перевизначення операторів "«" і ">>" для введення та виведення об'єктів, про форматування різних типів даних, а також про використання маніпуляторів введення-виведення. На завершення розділу переглянемо засоби файлового введення-виведення потокової інформації.
Порівняння С- та С++-систем введення-виведення
На сьогодні існують дві версії бібліотеки об'єктно-орієнтованого введення- виведення даних, причому обидві широко використовуються програмістами: стара [дод. А, 9], що базується на оригінальних специфікаціях мови С, і нова - визначається стандартом мови програмування С++. Стара бібліотека введення-виведен- ня даних підтримується за рахунок заголовного файлу <іоз(геат.И>, а нова - за допомогою заголовка <іоз(геат>. Нова бібліотека введення-виведення даних загалом є оновленою і вдосконаленою версією старої. Основна відмінність між ними полягає в механізмі реалізації засобів введення-виведення потокової інформації, а не у тому, як їх потрібно використовувати.
З погляду програміста, є дві істотні відмінності між старою С- і новою С++- бібліотеками введення-виведення. По-перше, нова бібліотека містить ряд додаткових засобів і визначає декілька нових типів даних. Тому нову бібліотеку С++-сис- теми введення-виведення можна вважати надбудовою над старою С-системою. Практично всі програми, що були написані раніше з використанням старої бібліотеки, успішно компілюються тепер за наявності нової бібліотеки, не вимагаючи внесення будь-яких значних змін у самій програмі. По-друге, стара бібліотека С- системи введення-виведення була визначена в глобальному просторі імен, а нова використовує простір імен біс) (пригадайте, що простір імен вісі використовується всіма бібліотеками стандарту мови програмування С++). Оскільки С-бібліотека введення-виведення даних вже дещо застаріла, то у цьому навчальному посібнику описується тільки нова її версія. Водночас велика частина наведеного нижче матеріалу повного мірою стосується і старої бібліотеки.
Поняття "потоків" у мові програмування C++
Принциповим для розуміння С++-СИСТЄМИ введення-виведення є те, що вона базується на понятті "потоку". Потік (stream) - це загальний логічний інтерфейс з різними пристроями, з яких складається комп'ютер. Потік або синтезує інформацію, або споживає її, після чого зв'язується з будь-яким фізичним пристроєм за допомогою С++-СИСТЄМИ введення-виведення. Характер поведінки всіх потоків є однаковим, незважаючи на різні фізичні пристрої, з якими вони пов'язуються. Оскільки різні потоки діють однаково, то практично до всіх типів пристроїв можна застосувати одні і ті ж самі функції та оператори введення-виведення. Наприклад, методи, що використовуються для виведення даних на екран, також можна використовувати для виведення їх на друкувальний пристрій або для запису у дисковий файл.
Файлові C++-потоки
У загальному випадку потік можна назвати логічним інтерфейсом з файлом. У мові програмування C++ до терміну "файл" належать дискові файли, екран монітора, клавіатура, порти, файли на магнітній стрічці й ін. Хоча файли між собою відрізняються за формою і можливостями представлення, проте робота з різними потоками інформації є однаковою. Перевага цього підходу (з погляду програміста) полягає у тому, що один пристрій комп'ютера може бути подібним до будь- якого іншого. Це означає, що потік забезпечує інтерфейс, який узгоджується зі всіма пристроями.
Потік зв язується з файлом у процесі виконання операції відкриття файлу, а відокремлюється від нього за допомогою операції його закриття.
Існує два типи потоків: текстовий і двійковий. Текстовий потік використовують для введення-виведення символів. При цьому можуть відбуватися деякі перетворення символів. Наприклад, під час виведення символ нового рядка може перетворюватися у послідовність символів: повернення каретки і переходу на новий рядок. Тому часто не буває взаємно-однозначної відповідності між тим, що посилається у потік, і тим, що насправді записується у файл. Двійковий потік можна використовувати з даними будь-якого типу, причому у цьому випадку ніякого перетворення символів не здійснюється, тобто між тим, що посилається у потік, і тим, що потім реально міститься у файлі, існує взаємно-однозначна відповідність.
Розглядаючи потоки, необхідно розуміти, що вкладається у поняття "поточної позиції". Наприклад, якщо довжина файлу дорівнює 100 байтів, і відомо, що вже прочитано його половину, то наступна операція зчитування почнеться на 50- му байті, який у цьому випадку і є поточною позицією.
Поточнаапо' иція — це те місце у файлі, з якого буде виконуватися наступна операція доступу до його даних.
Отже, у мові програмування C++ механізм введення-виведення потокової інформації функціонує з використанням логічного інтерфейсу, який називається потоком. Всі потоки мають аналогічні властивості, які дають змогу використовувати однакові функції введення-виведення, незалежно від того, з файлом якого типу існує зв'язок. Під файлом розуміють реальний фізичний пристрій, який містить дані. Якщо файли можуть відрізнятися між собою, то потоки - ні. Водночас, якщо деякі пристрої можуть не підтримувати всі операції введення-виведення даних (наприклад, операції з довільною вибіркою), то і пов'язані з ними потоки теж не підтримуватимуть ці операції.
Вбудовані С++-потоки
У мові програмування C++ міститься ряд вбудованих однобайтових (8-біто- вих) потоків (сіп, cout, cerr і clog), які автоматично відкриваються, як тільки програма починає виконуватися. Як уже зазначалося вище, сіп - це стандартний вхідний, a cout - стандартний вихідний потік. Потоки cerr і clog (вони призначені для виведення інформації про помилки) також пов'язані із стандартним виведенням даних. Різниця між ними полягає у тому, що потік clog є буферизованим, а потік cerr - ні. Це означає, що будь-які вихідні дані, послані у потік cerr, будуть негайно виведені на екран, а при використанні потоку clog дані спочатку записуються в буфер, а реальне їх виведення починається тільки тоді, коли буфер повністю заповнено. Зазвичай потоки cerr і clog використовують для виведення інформації на екран про стан відлагодження програми або її помилки.
У мові програмування C++ також передбачено двобайтові (16-бітові) символьні версії стандартних потоків, що іменуються wein, wcout, weerr і wclog. Вони призначені для підтримки таких мов як китайська, японська та інших східно- азійських, для представлення яких потрібні великі символьні набори. У цьому навчальному посібнику двобайтові стандартні потоки не розглядаються.
За замовчуванням стандартні С++-потоки зв'язуються з монітором, але програмним способом їх можна перенаправити на інші зовнішні пристрої або дискові файли. Перенаправлення може також виконати сама операційна система.