Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекції 1-8.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
6.11 Mб
Скачать

Лекція 4

Область дії об’єкта. Правила доступу до компонентів класу

Кожен об'єкт класу має власну копію всіх даних-членів класу. Бувають випадки, коли одна копія змінної повинна спільно вико­ристовуватися всіма об'єктами класу. Тоді застосовується статич­на змінна класу. Очевидно, що статичні члени класу існують тоді коли не існує ніяких об'єктів цього класу. Оголошення статичних членів класу починається з ключового слова static. Статичні дані-члени мають область дії клас і повинні ініціалізуватися один раз в області дії файлу. Доступ до відкритих статичних членів класу можливий за допомогою будь-якого об'єкта класу або за допомо­гою імені класу і бінарної операції дозволу області дії. Для досту­пу до відкритого статичного члена, перед даним-членом ставиться позначення класу і потім бінарна операція дозволу області дії (C++), або позначення класу і символу крапка (С#). Наприклад, у мові C++:

class Empl

{

public:

setCount(int);

static int getCount();

private:

static int count;

};

int main() {

Empl *pEmpl;

pEmpl = new Empl;

pEmpl > setCount(10);

delete pEmpl; count = getCountC);

}

Приклад у мові C#:

class Empl {

public setCount(int)

{…};

public static int getCountQ {…};

private static int count = 10;

int main()

}

Empl empl;

mpl - new Empl();

empl.setCount(10);

int count = Empl.getCountQ;

Програмні конструкції, які можуть використовувати методи і значення об'єкта, створеного на основі класу, називаються компо­нентами класу і діляться на три групи:

- ресурси похідного класу;

- «друзі» класу - підпрограми і класи, оголошені спеціальним

чином;

- звичайні підпрограми - не «є», ні ресурсами класу, ні «друзя­ми» класу.

Для обмеження доступу до компонентів базового класу і забез^ печення ефективної організації взаємодії об'єктів, які створюються на основі класів, доступ до компонентів базового класу, і отже, до компонентів об'єкта, створеного на основі цього класу, регулюєть­ся за допомогою спеціальних правил. Ці правила визначають об­ласть видимості членів класу і тим самим область дії. Правила за­стосовуються до частин класу. У зв'язку з цим у тілі класу зазвичай передбачається три такі частини:

- закрита (private);

- захищена (protected);

- відкрита (public).

За умовчанням всі члени класу є закритими (private). Визначаються такі правила доступу до вказаних частин класу

(рис 1.7):

- частини, оголошені, як закриті, доступні методам даного кла­су і друзям класу;

- частини, оголошені, як захищені, доступні методам даного класу, методам похідного класу і друзям класу;

- частини, оголошені, як відкриті, доступні будь-яким конст­рукціям програми.

Рис. 1.7. Схема взаємодії конструкцій

Передбачається, що члени, представлені у відкритій частині, показують доступні ресурси класу (інтерфейс). Члени закритої частини і реалізація членів відкритих частин недоступні клієнтам класу і представляють реалізацію ресурсів класу.

Проте методи цього класу і «друзі» можуть мати доступ до чле­нів закритих частин класу, а опис даних закритої частини видно користувачеві класу. Цей недолік організації класів порушує прин­цип приховування інформації. Наприклад:

#include «timel.h»

int main ()

{

Time t;

// Помилка: Time: :hour' недоступно

t.hour = 7:

}

Наприклад class Airplanes

{

private:

Airplane_Data Database [100];

class AN 140 : Airplanes

void process_AN140(int);

void AN 140 :: process_AN140(int i)

Airplane_Data MyData = Database [і]; //помилка досту-

пу

};

}

До того ж, якщо оголошений об'єкт MyAN140 класу AN 140, то він міститиме пам'ять для даних Database члена базового класу Airplanes. Якби Database був членом захищеної частини, то до нього можна було б звертатися з похідного класу. Однак надійніше, якщо похідний клас маніпулює успадкованими компонентами, використовуючи загальні або захищені частини.

Частини класу можуть бути розташовані у будь-якому порядку, проте їх рекомендується розміщувати так: спочатку відкриті, потім захищені і, нарешті закриті.

Доступ до private-частини класу. «Дружні» підпрограми

У мові C++ передбачається обхід механізму приховування ін формації шляхом застосування спеціальних підпрограм, які нази ваються «дружніми» функціями (підпрограмами). У класі підпрог рами описуються прототипами з ключовим словом friend, а визна чаються поза класом, до ресурсів яких вони мають доступ. Наприклад: class WithFrend і

friend void setX(WithFriend &, int); public:

private;

int x;

void setX(WithFriend &c, int val)

/

I

c.x ~. val;

main () І

WithFriend obj; setX(obj, 10);

З прикладу бачимо, що зв'язок «дружньої» підпрограми з prí­vate частиною класу встановлюється через позначення об'єкта як фактичний параметр, а оператор дозволу видимості (::) у цьому випадку не використовується.

Окрімттідпрограм «друзями» класу можуть бути інші класи, що мають такий же доступ до private-частини, як і «дружні» функції: class One

{

public:

friend class Two;

Механізм «дружності» не має властивостей симетричності і транзитивності.

Оператор привласнення для об'єктів

У мовах C++ і С# передбачається форма оператора привлас­нення, яка може використовуватися для привласнення значень од­ного об'єкта іншому. Обидва об'єкти мають належати до одного

класу.

Наприклад, у мові С#:

class AssStat {

public:

private:

main

t

int nVal; char с Val;

A ssStat obj 1 ; AssStat obj2;

оЬ]2 = оЬ)1;

і

У мові С++ наведена форма оператора привласнення назива­ється побітовим копіюванням за умовчанням.

Реалізується привласнення побітовим копіюванням, тому, якщо в класі використовується динамічний розподіл пам'яті, то правиль­не виконання оператора привласнення не гарантується.

Спеціальні методи класу

Значення даних-членів класу можна встановити за допомогою методів класу після створення об'єкта. Також можна виконати по­трібні для знищення об'єкта дії. Проте в класах передбачаються опис і використання двох типів спеціальних методів, які назива­ються «конструктори» і «деструктори», які частково виконують вказані дії.

Конструктори - спеціальні методи, реалізуються як закриті підпрограми, створюють екземпляри класу. Суть створення об'єкта полягає в тому, щоб захопити пам'ять для об'єкта (як правило, ра­зом) та ініціалізувати початковими значеннями компоненти-даних об'єкта, що описані в класі, на основі якого створюється об'єкт. Таким чином, коли необхідно створити об'єкт, викликається конс­труктор класу.

У мовах програмування С++ і С# існують такі правила для ого­лошення конструкторів:

- позначення конструктора мас бути таким же, як і позначення класу;

~ конструктор може мати список параметрів.

Розрізняють три типи конструкторів - за умовчанням, копію­вання, додатковий.

Конструктор за умовчанням. У мові C++ він називається void-конструктор та реалізується за допомогою закритої підпрограми без параметрів або із списком параметрів, призначених за умовчанням.

Конструктор копіювання. У мові C++ він називається сору-конструкгор та реалізується за допомогою закритої підпрограми з одним параметром. Параметр є посиланням, що типізований кла­сом. До того ж, значення компонентів-даних створюваного об'єкта копіюються з уже створеного об'єкта класу вказаного типу в ново­створюваний. Копіювання, яке здійснює «штатний» конструктор-копіювання, називається поверхневим і засноване на операторі привласнення. Суть його роботи полягає в такому: якщо дані-компоненти об'єкта є вказівними змінними та ініційовані посилан­нями на динамічну пам'ять в групі, а копіювання здійснилося, то коли один об'єкт знищується — в результаті звільняється пам'ять, зайнята значеннями, але другий об'єкт (копія) вказуватиме на зві­льнену ділянку пам'яті, що звичайно неприпустимо. Щоб уникнути цього застосовується глибоке копіювання, коли значення, розміще­ні в динамічній пам'яті в купі, переносяться на нові ділянки пам'яті об'єкта, який створюється.

Наприклад, у мові C++: class А {

public:

А(); А (А&);

int getIntA();

private:

int * iintA; int * intB;

i.

Конструктор з глибоким копіюванням:

А :: А(А & г) {

intA - new int; intB = new int; *intA Ш r.getlntAQ; ftntB = * (r.intB);

Наприклад, у мові C#:

public A() {

InitO;

public A(A r)

itsA = r.getItsA(): itsB = r.itsB;

і

public int getftsAQ

return itsA;

private int itsA; private int itsB; private void Init()

itsA= 1; itsB = 2:

Додатковий конструктор - забезпечує список будь-яких фор­мальних параметрів, за допомогою якого компоненти-дані об'єкта ініціалізувалися значеннями фактичних параметрів.

Реалізуючи конструктори класу, використовуємо механізм пе­ревантаження підпрограм, тому всі конструктори класу мають од­накове позначення, але різні реалізації.

Якщо в класі не оголошений конструктор, то він створюється, як правило, автоматично у формі конструктора за умовчанням для цього класу.

Всі конструктори реалізуються у формі процедур^__

Деструктори - це спеціальні методи класу, які ліквідують ек­земпляри класу (об'єкти), коли настає кінець періоду їх існування. Суть ліквідації полягає у звільненні пам'яті зайнятою під об'єкт конструктором у групі.

У мовах C++ і С# для деструкторів передбачені такі правила:

- позначення деструктора повинне збігатися з позначенням класу і перед ним має стояти символ «~»;

- деструктор у класі передбачається тільки один;

- деструктор реалізується у формі процедури без параметрів;

- якщо у класі не оголошений деструктор, то він створюється автоматично;

- якщо настав кінець області існування об'єкта і деструктор не викликаний вручну, то він викликається автоматично.

Окрім звільнення пам'яті, деструктор виконує всі дії, протиле­жні діям відповідного конструктора. Наприклад, у мові C++:

class myclass();

{ public:

mvclass()

{

m_nl - 0;

myclass (myclass &(obj)) {

m_nl = obj.mnl;

void set mn!(int NewVal)

\

m_nl = NewVal;

int getmnl(); t

return m nl;

~myclass(); private:

intm nl

mam()

}

int nVal;

my class objl; // оголошення об'єкта класу my class

obj.set m_nl(10);

nVal = getm_nl();

my class obj2;

my class (obj 1);

nVal = obj2. get m_nl();