Розробка власного класу STRING
Курсовой проект - Компьютеры, программирование
Другие курсовые по предмету Компьютеры, программирование
?вно. Особливо часто така необхідність виникає у звязку з оператором new. Розглянемо приклад.
Коли ми пишемо:
char *arena = new char [sizeof Image];
то з купи виділяється память, розмір якої дорівнює розміру обєкта типу Image, вона не ініціалізована й заповнена випадковими бітами.
Якщо ж написати:
Image *ptr = new (arena) Image ("Quasimodo");
то ніякої нової памяті не виділяється. Замість цього змінної ptr привласнюється адреса, асоційованою зі змінною arena. Тепер память, на яку вказує ptr, інтерпретується як займана обєктом класу Image, і конструктор застосовується до вже існуючої області. Таким чином, оператор розміщення new () дозволяє сконструювати обєкт у раніше виділеній області памяті.
Закінчивши працювати із зображенням Quasimodo, ми можемо зробити якісь операції із зображенням Esmerelda, розміщеним по тій же адресі arena у памяті:
Image *ptr = new (arena) Image ("Esmerelda");
Однак зображення Quasimodo при цьому буде затерто, а ми його модифікували й хотіли б записати на диск. Звичайне збереження виконується в деструкторі класу Image, але якщо ми застосуємо оператор delete:
// погано: не тільки викликає деструктор, але й звільняє память
delete ptr;
то, крім виклику деструктора, ще й повернемо в купу память, чого робити не варто було б. Замість цього можна явно викликати деструктор класу Image:
ptr->~Image ();
зберігши відведену під зображення память для наступного виклику оператора розміщення new.
Відзначимо, що, хоча ptr і arena адресують ту саму область памяті в купі, застосування оператора delete до arena
// деструктор не викликається
delete arena;
не приводить до виклику деструктора класу Image, тому що arena має тип char*, а компілятор викликає деструктор тільки тоді, коли операндом в delete є вказівник на обєкт класу, що має деструктор.
1.11 Небезпека збільшення розміру програми
Вбудований деструктор може стати причиною непередбаченого збільшення розміру програми, оскільки він вставляється в кожній точці виходу всередині функції для кожного активного локального обєкта. Наприклад, у наступному фрагменті
Account acct ("Tina Lee");
int swt;
// ...
switch (swt) {
case 0:
return;
case 1:
// щось зробити
return;
case 2:
// зробити щось інше
return;
// і так далі
}
компілятор підставить деструктор перед кожною інструкцією return. Деструктор класу Account невеликий, і витрати часу й памяті на його підстановку теж малі. У противному випадку прийдеться або обявити деструктор невбудованим, або реорганізувати програму. У прикладі вище інструкцію return у кожній мітці case можна замінити інструкцією break для того, щоб у функції була єдина точка виходу:
// переписано для забезпечення єдиної точка виходу
switch (swt) {
case 0:
break;
case 1:
// щось зробити
break;
case 2:
// зробити щось інше
break;
// і так далі
}
// єдина точка виходу
return;
1.12 Константні обєкти й функції-елементи
Ми ще раз особливо відзначаємо принцип найменших привілеїв як один з найбільш фундаментальних принципів створення гарного програмного забезпечення. Розглянемо один зі способів застосування цього принципу до обєктів.
Деякі обєкти повинні допускати зміни, інші - ні. Програміст може використовувати ключове слово const для вказівки на те, що обєкт незмінний - є константним і що будь-яка спроба змінити обєкт є помилкою. Наприклад,
const Time noon (12, 0, 0);
обявляє як константний обєкт noon класу Time і присвоює йому початкове значення 12 годин пополудні.
Компілятори C++ сприймають оголошення const настільки неухильно, що в підсумку не допускають ніяких викликів функцій-елементів константних обєктів (деякі компілятори дають у цих випадках тільки попередження). Це жорстоко, оскільки клієнти обєктів можливо захочуть використати різні функції-елементи читання "get", а вони, звичайно, не змінюють обєкт. Щоб обійти це, програміст може оголосити константні функції-елементи; тільки вони можуть оперувати константними обєктами. Звичайно, константні функції-елементи не можуть змінювати обєкт - це не дозволить компілятор.
Константна функція вказується як const і в обяві, і в описі за допомогою ключового слова const після списку параметрів функції, але перед лівою фігурною дужкою, що починає тіло функції. Наприклад, у наведеному нижче прикладі обявляється як константна функція-елемент деякого класу А
int A:: getValue () const {return privateDateMember};
яка просто повертає значення одного з даних-елементів обєкта. Якщо константна функція-елемент описується поза обявою класу, то як обява функції-елемента, так і її опис повинні включати const.
Тут виникає цікава проблема для конструкторів і деструкторів, які звичайно повинні змінювати обєкт. Для конструкторів і деструкторів константних обєктів оголошення const не потрібно. Конструктор повинен мати можливість змінювати обєкт із метою присвоювання йому відповідних початкових значень. Деструктор повинен мати можливість виконувати підготовку завершення робіт перед знищенням обєкта.
Програма на мал.4 створює константний обєкт класу Time і намагається змінити обєкт не константними функціями-елементами setHour, setMinute і setSeco