
- •Міністерство надзвичайних ситуацій України Львівський державний університет безпеки життєдіяльності Юрій грицюк, Тарас рак
- •Навчальний посібник
- •Потреба використання об'єктно-орієнтованого програмування
- •Поняття про об’єктно-орієнтований підхід до розроблення складних програм
- •Основні компоненти об’єктно-орієнтованої мови програмування
- •Поняття про універсальну мову моделювання
- •Базові поняття класу
- •Код програми 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;
- •«" 'Є' для запису витрат:";
- •Навчальний посібник
Int mainO
{
strClass Obj; // Створення об'єкта класу
// Присвоюємо об'єкт, повернутий функцією InitO, об'єкту Obj.
Obj = lnit(); // Ця настанова генерує помилку!!!!
Obj.ShowO; Ч Відображення "сміття".
getchO; return 0;
}
Результати виконання цієї програми мають такий вигляд:
Введіть рядок: Привіт Звільнення s-пам'яті.
Звільнення s-пам'яті. s= тут появиться сміття Звільнення s-пам'яті.
Зверніть увагу на те, що виклик деструктора -strClassO відбувається тричі! Вперше він викликається при виході локального об'єкта obj з області видимості у момент його повернення з функції init(). Другий виклик деструктора ~strClass() B№ бувається тоді, коли руйнується тимчасовий об'єкт, який повертається функцією InitO- Коли функція повертає об'єкт, то автоматично створюється невидимий (для Вас) тимчасовий об'єкт, який зберігає повернуте значення. У нашому випадку цей об'єкт просто є побітовою копією об'єкта obj. Отже, після повернення з функції використовується деструктор тимчасового об'єкта. Оскільки область пам'яті, що виділяється для зберігання рядка, який вводить користувач, вже була звільнена (причому двічі!), то під час виклику функції ShowO на екран буде виведено "сміття"1.
Нарешті, після завершення роботи коду програми викликається деструктор об'єкта ОЬІ, який належить функції таіп(). Ситуація тут ускладнюється ще й тим, що під час першого виклику деструктора звільняється область пам'яті, виділена для зберігання рядка, отримуваного функцією ІпгїО. Таким чином, у цій ситуації погано не тільки те, що решта два звернення до деструктора -БШаБзО спробують звільнити вже звільнену динамічно виділену область пам'яті, але вони можуть зруйнувати систему динамічного розподілу пам'яті.
Тут важливо зрозуміти, що при поверненні об'єкта з функції для тимчасового об'єкта, який зберігає побітову копію об'єкта оЬІ, буде викликано його деструктор. Тому потрібно уникати повернення об'єктів у ситуаціях, коли це може мати згубні наслідки. Для вирішення цього питання замість повернення об'єкта з функції доцільно використати повернення покажчика або посилання на об'єкт. Але здійснити це не завжди вдається. Ще один спосіб вирішення цього питання полягає у використанні конструктора копії, механізм реалізації якого розглянемо у наступному підрозділі.
Механізми створення та використання конструктора копії
Одним з важливих форматів застосування перевизначеного конструктора є конструктор копії об'єкта. Як було показано в попередніх прикладах, при передачі об'єкта функції або при поверненні його з неї можуть виникати певні проблеми. Один із способів їх уникнення полягає у використанні конструктора копії, який є спеціальним типом перевизначеного конструктора.
Основна причина використання конструктора копії полягає у тому, що при передачі об'єкта функції створюється побітова (тобто точна) його копія, яка передається параметру цієї функції. Проте трапляються ситуації, коли така однакова копія об'єкта небажана. Наприклад, якщо оригінальний об'єкт містить покажчик на динамічно виділену область пам'яті, то і покажчик, який належить побітовій копії об'єкта, також посилатиметься на ту ж саму область пам'яті. Отже, якщо у копію об'єкта будуть внесені зміни у вміст цієї області пам'яті, то ці зміни стосуватимуться також оригінального об'єкта! Понад це, внаслідок завершення роботи функції, побітова копія об'єкта буде зруйнована за викликом деструктора, що негативно відобразиться на початковому об'єкті.
Аналогічна ситуація виникає при поверненні об'єкта з функції. Компілятор генерує тимчасовий об'єкт, який зберігає побітову копію об'єкта, що повертається функцією2. Цей тимчасовий об'єкт виходить за межі області видимості функції відразу ж, як тільки ініціатору виклику цієї функції буде повернуте "обіцяне" значення, після чого негайно викликається деструктор тимчасового об'єкта. Оскільки цей деструктор руйнує область пам'яті, потрібну для виконання далі коду програми, то наслідки її роботи будуть невтішні.
Основна причина виникнення цієї проблеми полягає у створенні побітової копії об'єкта. Щоб запобігти їй, необхідно точно визначити, що повинно відбува
тися, коли створюється така копія об'єкта, і, тим самим, уникнути небажаних побічних ефектів. Цього можна домогтися шляхом створення конструктора копії об'єкта.
Найпоширеніший формат конструктора копії об'єкта має такий вигляд:
ім'я_класу (const ім'я_класу &obj]
{
// Тіло конструктора копії
}
У цьому записі елемент &obj означає посилання на об'єкт, який використовується для ініціалізації іншого об'єкта.
У мові програмування C++ визначено дві ситуації, у яких значення одного об'єкта передається іншому: при присвоєнні та ініціалізації. Ініціалізація об'єкта може виконуватися трьома способами, тобто у випадках, коли:
один об'єкт безпосередньо ініціалізує інший об'єкт, як, наприклад, в оголошенні;
копія об'єкта передається як аргумент параметру функції;
генерується тимчасовий об'єкт (найчастіше як значення, що повертається функцією).
Наприклад, нехай завчасно створено об'єкт ObjY типу myClass. Тоді у процесі
виконання таких подальших настанов буде викликано конструктор копії класу myClass:
myClass ObjX = ObjY; // Об'єкт ObjY безпосередньо ініціалізує об'єкт ObjX.
Fun1 (ObjY); // Об'єкт ObjY передається як аргумент
ObjY = Fun2(); // Об'єкт ObjY приймає об'єкт, що повертається функцією.
У перших двох випадках конструктору копії буде передано посилання на об'єкт ObjY, а в третьому - посилання на об'єкт, який повертається функцією Fun2().
Bapmoa нати! Конструктори копії не роблять ніякого впливу на операції
присвоєння.
Щоб глибше зрозуміти призначення конструктора копії, розглянемо Грунтовніше його значення у кожній з цих трьох ситуацій.