на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Розробка власного класу 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_H

class Time { public:

Time (int = 0, int = 0, int = 0); // конструктор за замовчуванням

// функції запису set

void 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-23

int minute; // 0-59

int 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: SS

void 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
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент.