|
Розробка власного класу STRING |
еструктор не викликається, коли з області видимості виходить посилання або вказівник на об'єкт (сам об'єкт при цьому залишається).С++ за допомогою внутрішніх механізмів перешкоджає застосуванню оператора delete до вказівника, що не адресує ніякого об'єкта, так що відповідні перевірки коду необов'язкові: // необов'язково: неявно виконується компіляторомif (pact! = 0) delete pact;Щораз, коли усередині функції цей оператор застосовується до окремого об'єкта, розміщеному в купі, краще використати об'єкт класу auto_ptr, а не звичайний вказівник. Це особливо важливо тому, що пропущений виклик delete (скажемо, у випадку, коли збуджується виключення) веде не тільки до витоку пам'яті, але й до пропуску виклику деструктора. Нижче приводиться приклад програми, переписаної з використанням auto_ptr (вона злегка модифікована, тому що об'єкт класу auto_ptr може бути явно із для адресації іншого об'єкта тільки присвоюванням його іншому auto_ptr):#include <memory>#include "Account. h"Account global ("James Joyce");int main (){Account local ("Anna Livia Plurabelle", 10000);Account &loc_ref = global;auto_ptr<Account> pact (new Account ("Stephen Dedalus"));{Account local_too ("Stephen Hero");} // об'єкт auto_ptr знищується тут}1.10 Явний виклик деструктораІноді викликати деструктор для деякого об'єкта доводиться явно. Особливо часто така необхідність виникає у зв'язку з оператором 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 і setSecond. Як результат показані згенеровані компілятором Borland C++ попередження. // TIME5. H // Оголошення класу Time. // Функції-елементи описані в TIMES. CPP#ifndef TIME5_H idefine TIME5_Hclass Time { public:Time (int = 0, int = 0, int = 0); // конструктор за замовчуванням // функції запису setvoid setTime (int, int, int); // установкачасуvoid setHour (int); // установкагодинvoid setMinute (int); // установкахвилинvoid setSecond (int); // установкасекунд // функції читання get (звичайно об'являється const)int getHour () const; // повертає значення годинint getMinute () const; // повертає значення хвилинint getSecondf) const; // повертає значення секунд // функції друк (звичайно об'являється const)void printMilitary () const; // друк військового часу void printStandard () const; // друк стандартного часуprivate:int hour; // 0-23int minute; // 0-59int second; // 0-59};#endif // TIME5. CPP // Опис функцій-елементів класу Time.finclude <iostream. h>iinclude "time5. h" // Функція конструктор для ініціалізації закритих даних. // За замовчуванням значення рівні 0 (дивися опис класу). Time:: Time (int hr, int min, int sec) { setTime (hr, min, sec); } // Встановка значень години, хвилин і секунд, void Time:: setTime (int h, int m, int s) {hour = (h >= 0 && h < 24)? h: 0;minute = (m >= 0 && m < 60)? m: 0;second = (s >= 0 && s < 60)? s: 0; } // Установка значення годинvoid Time:: setHour (int h) { hour = (h >= 0 && h < 24)? h: 0; } // Установка значення хвилин void Time:: setMinute (int m){ minute = (m >= 0 && m < 60)? m: 0; } // Установка значення секунд void Time:: setSecond (int s){ second = (s >= 0 && s < 60)? s: 0; } // Читання значення годинint Time:: getHour () const { return hour; } // Читання значення хвилинint Time:: getMinute () const { return minute; } // Читання значення секундint Time:: getSecond () const { return second; } // Відображення часу у військовому форматі: HH: MM: SSvoid Time:: printMilitary () const{cout " (hour < 10?"0": "")" hour " ": "" (minute < 10?"0": "")" minute" ": "" (second < 10?"0": "")" second; } // Відображення часу в стандартному форматі: HH: MM: SS AM // (або РМ)void Time:: printStandard () const {cout " ( (hour == 12)? 12: hour% 12)" ": "" (minute < 10?"0": "")" minute " ": " " (second < 10?"0": "")" second " (hour< 12?"AM": "PM"); } // FIG7_1. CPP // Спроба одержати доступ до константного об'єкта // з не-константними функціями-елементами.#include <iostream. h>#include "time5. h"main () {const Time t (19, 33, 52); // константний об'єктt. setHour (12); // ПОМИЛКА: не-константна функція елемент t. setMinute (20); // ПОМИЛКА: не-константна функція елемент t. setSecond (39); // ПОМИЛКА: не-константна функція елементreturn 0; }Compiling FIG7_1. CPP:
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
|
|
© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент. |
|
|