заміни вмісту покажчика на адресу нової області.
При ініціалізації об'єкту значеннями полів іншого об'єкту, як наголошувалося в розділі 3.2, використовується копіюючий конструктор. Крім того, якщо об'єкт є параметром деякої функції, передаваним по значенню, усередині цієї функції створюється копія такого об'єкту, при побудові якої також застосовується копіюючий конструктор. Якщо копіюючий конструктор у визначенні класу не передбачений, він створюється за умовчанням. При використовуванні динамічних полів, результат дії такого конструктора не передбачив, оскільки компілятор не може точно визначити розміри копійованих полів. В цьому випадку користувач повинен передбачити власний копіюючий конструктор, що забезпечує грамотне виконання дій, передбачених при копіюванні.
Слід також відзначити особливості реалізації оператора привласнення. Як вже наголошувалося, операція привласнення значень полів одного об'єкту іншому передбачена за умовчанням. Проте використовування динамічних полів об'єкту приводить до не зовсім коректного її виконання. Операція привласнення здійснюється, як і при роботі копіюючого конструктора, поле за полем. Оскільки реальним вмістом полів є покажчики, то відбувається заміна старої адреси на новий. При цьому пам'ять, що раніше адресується покажчиком, залишиться не звільненою, оскільки адреса її буде втрачений. Тому рекомендується в описі класу передбачити перевизначення операції привласнення з урахуванням всіх особливостей роботи з виділенням і звільненням пам'яті для полів визначуваного класу (див. приклад 3.30).
Динамічні об'єкти із статичними полями. Як і на інші типи даних, на об'єкт будь-якого класу можна посилатися через покажчик. При цьому значення йому можна привласнити за допомогою операції узяття адреси (в цьому випадку він може адресувати і статичний об'єкт). Проте більш ефективно використати покажчики для реалізації механізму динамічного розподілу пам'яті під об'єкт з вільної області.
Оскільки типом об'єкту є деякий клас, то стосовно об'єктів використовується наступна форма звернення до функції New:
< ім'я_покажчика_на_об'єкт > = new < ім'я_класу >;
або
< ім'я_покажчика_на_об'єкт >==new< ім'я клacу >(< cписoк _ пapaмeтрів >);
Друга форма використовується при наявності в конструктора списку параметрів.
Функція delete вимагає вказівки тільки імені об'єкту:
delete < ім'я покажчика на об'єкт >;
Необхідно відзначити також особливості роботи з динамічними об'єктами класів, що входять в деяку ієрархію. Як вже наголошувалося, C++ дозволяє привласнювати покажчикам на базовий клас, значення покажчиків на будь-який з похідних від нього. В цьому випадку виникають проблеми з доступом до полів об'єкту, описаних в похідному класі:
покажчик на об'єкт базового класу пов'язаний з описом його полів, і поля, описані в похідному класі для нього «невидимими» (рис 1.25). Тому при звертанні через покажчик на базовий клас до полів похідного об'єкту необхідно засобами мови явно перевизначити («привести») тип покажчика;
крім того, якщо при визначенні покажчика на базовий клас створюється динамічний об'єкт похідного класу, то під час знищення такого об'єкту викликається деструкція лише базового класу і пам'ять звільняється не коректно, оскільки деструкція не може правильно визначити розміри пам'яті, що звільняється. Ця проблема розв'язується застосуванням віртуальної деструкції. Якщо при оголошенні деструкції базового класу описати його як virtual, то всі конструктори похідного класу також будуть віртуальними. При знищенні об'єкту за допомогою оператора delete через покажчик на базовий клас будуть коректно викликані деструкції всіх похідних класів. Всі ці особливості мають місце і при роботі з поліморфними об'єктами (роздягнув 3.4)
Необхідно ще раз відзначити особливості виконання операції привласнення при роботі з об'єктами через покажчики. Річ у тому, що привласнення одного об'єкту іншому за допомогою покажчиків зводиться до переадресації цього покажчика: після виконання операції перший покажчик містить ту ж адресу, що і другий - адреса другого об'єкту. Старе значення адреси (адреса першого об'єкту) стирається, і пам'ять, виділена раніше під перший об'єкт, залишається не звільненою. З другого боку, при спробі знищити об'єкти по покажчиках виникає помилка, оскільки одна і та ж ділянка пам'яті, виділена під другий об'єкт, звільняється двічі. Щоб уникнути цих помилок необхідно ураховувати і контролювати подібні ситуації (приклад 3.37).
На клас, використовуваний для динамічних об'єктів, можна покласти задачу управління пам'яттю, якщо перевизначити operator new() і operator delete(). Особливо це корисно для класів, які є базовими для численних похідних класів.
Динамічні об'єкти з динамічними полями. Такі об'єкти поєднують характерні особливості статичних об'єктів з динамічними полями і динамічних об'єктів.
Всі вищенаведені приклади припускають наявність безмежній або достатнє великій динамічній (вільній) пам'яті. Проте реально ця пам'ять кінцева, і при великій кількості об'єктів і значній кількості пам'яті під їхні поля може наступити ситуація, коли пам'ять або черінь сам об'єкт, або під його поля не може бути виділена. В такому разі в конструкторі або функції, що виконує розподіл, слід передбачити контроль наявності пам'яті. При виявленні недоліку пам'яті необхідно визначити, в який момент виникла ситуація (при розподілі пам'яті під об'єкт або черінь поле), а потім грамотно вийти з положення, що створилося.
“Технологія програмування та створення програмних продуктів”
ТЕОРЕТИЧНІ ПИТАННЯ З ПРЕДМЕТУ: “ТЕХНОЛОГІЯ ПРОГРАМУВАННЯ ТА СТВОРЕННЯ ПРОГРАМНИХ ПРОДУКТІВ “
9. Технологія COM. Основні елементи та використання технології COM.
Компоненти використовуються для того щоб виконувати набір операцій, реалізація яких є закритою для клієнтів компонента, а інтерфейс використовується для доступу до операцій цього компонента.
Інтерфейс – це набір правил, які повинні додержуватися усі класи або компоненти, що його реалізують.
COM(Component Object Model) – одна з базових технологій Windows, основна ціль якої – це забезпечення можливості експорту об’єктів. Ідея експорту полягає в тому, що один модуль створює об’єкт, а інші його ввикористовують, при звертанні до його методів із серверів.
Модулі.
Відповідно до цього рисунка маємо