Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП_Лаб_Гриф.doc
Скачиваний:
7
Добавлен:
14.11.2019
Размер:
2.81 Mб
Скачать

Виклик деструкторів

Виклик деструктора виконується неявно, коли об'єкт виходить зі своєї оголошеної області дії. Для локальних перемінних деструктори викликаються, коли перестає бути активним блок, у якому вони оголошені. У випадку, коли оголошені глобальні об'єкти-перемінні, деструктори викликаються як частина процедури виходу після закінчення функції main( ).

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

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

Хід роботи

  1. Вивчити теоретичні відомості.

  2. Відповідно до індивідуального завдання для попереднього заняття (таблиця 20.1) розробити конструктори і деструктор для заданого базового класу. Здійснити ініціалізацію об'єктів класу різними конструкторами. Розмістити об'єкт класу в динамічній пам'яті і зруйнувати його після використання в програмі.

  3. Набрати програму на комп'ютері й усунути помилки.

  4. Одержати результат.

  5. Оформити звіт.

  6. Підготуватися до захисту заняття, вивчивши контрольні питання по даній темі.

Вимоги до змісту звіту приведені в занятті №1.

Питання для контролю і самостійної роботи

  1. Навіщо використовуються конструктори і деструктори ?

  2. Яке ім'я має конструктор і деструктор ?

  3. Скільки конструкторів і деструкторів може бути в класі ?

  4. Чи можна виконати ініціалізацію даних-членів без конструктора ?

  5. Назвіть відмінності конструкторів і деструкторів від інших функцій.

  6. Чи можна явно викликати конструктор і деструктор ?

  7. Чи можна передати параметри в конструктори, використовувати параметри за умовчанням ?

  8. Як визначити конструктор, який буде викликаний, якщо їх декілька ?

  9. Що таке конструктор за умовчанням, конструктор копіювання ?

  10. Приведіть синтаксис оголошення, визначення і використання конструкторів, які альтернативні варіанти припустимі ?

  11. Поясніть приведені в теоретичній частині приклади.

  12. Для чого необхідні оператори new і delete, як їх застосувати ?

  13. Коли викликаються деструктори для локальних і глобальних перемінних?

  14. Як відбувається виклик деструкторів при виході з програми, при виклику функцій ехit( ), abort( ) ?

Заняття№22

Використання спадкування для створення ієрархії класів

(2 години)

Ціль роботи: одержати навички у використанні спадкування для створення похідних класів при простому спадкуванні.

Теоретичні відомості

При оголошенні похідного класу базові класи перелічуються у списку розділені комою. Перед класами у списку базових класів задаються специфікатори доступу: public, private або protected.

Синтаксис оголошення похідного класу

сlass <Ім'я_похідного_класу> : <Базові_класи> { <Список_елементів> };

Наприклад, при оголошенні похідного класу Der базові класи перелічуються у списку: В1, В2 ... з необхідними специфікаторами доступу

class Der : public B1, private B2, ... { ... };

Ці специфікатори не змінюють доступу до елементів з погляду базового класу, але можуть змінити доступ до елементів базових класів з похідних класів. Якщо Der являє собою оголошення класу (class), то за умовчанням використовується private, а якщо Der - оголошення структури (struct), те public.

Клас Der успадковує всі елементи базових класів. (Перевизначені елементи базових класів також успадковуються і при необхідності доступ до них можливий за допомогою перевизначень області дії). Клас Der може використовувати елементи базових класів тільки з атрибутами public і protected.

Похідний клас успадковує атрибути доступу базового класу у такий спосіб:

1 Якщо базовий клас зазначений у списку як public:

  • елементи public базового класу залишаються елементами public для похідного класу;

  • елементи private і protected базового класу залишаються відповідно елементами private і protected похідного класу.

2 Якщо базовий клас protected:

  • загальнодоступні (public) і захищені (protected) елементи базового класу стають захищеними (protected) елементами похідного класу;

  • елементи private базового класу залишаються private для похідного класу.

3 Якщо базовий клас private:

  • загальнодоступні (public) і захищені (protected) члени базового класу стають частними (private) елементами похідного класу;

  • елементи private базового класу залишаються private для похідного класу.

В усіх розглянутих випадках відзначимо, що елементи private базового класу були і залишаються недоступними для функцій-членів похідного класу, поки в похідному класі не використаний оператор дозволу області видимості (::) або поки в оголошенні доступу базового класу не будуть явно задані оголошення friend для інших класів чи їх функцій-членів.

Приклади:

class X : A { // Клас X є похідним від класу А (просте спадкування),

// причому за умовчанням специфікатор - private A

};

class Y : B, public C { // Клас Y є похідним (множинне спадкування)

// від B і C. Специфікатор для С – public, за умовчанням: private B

};

struct S : D { // Структура struct S - похідна від D, за умовчанням

// для структур маємо - public D

};

struct T : private D, E { // Структура struct T є похідною (множинне

// спадкування) від D і E. Специфікатор для D – private D.

// За умовчанням для E - public E

};

Дію специфікаторів доступу до елементів базових класів при спадкуванні можна скорегувати за допомогою оператора дозволу області видимості (::) у розділах public чи protected для похідного класу.

Приклади:

class B { //Базовий клас

int a; //За умовчанням

// розділ private

public:

int b, m;

int Bfunc(void);

};

class X : private B {//Х- клас-спадкоємець класу B

int d; // За умовчанням private

public:

B::m; // Перемінна B::m була private, тепер

int e; // вона стала public

int Xfunc(void);

};

Члени базового класу В:: a, b, m і Bfunc( ) - стали private у класі-спадкоємці Х. Перемінна а в Х недоступна. Функція Xfunc( ) у X є функцією-членом, тому вона має доступ:

  • до усіх власних private і public елементов: d, e і Xfunc( ).

  • до елементів b і Bfunc( ) базового класу В, які стали private. Однак, Xfunc( ) не має доступу до private відносно B елемента a.

  • до перемінної m класу В, яка явно задана public з допомогою (::) – B::m.

Якщо функція є зовнішнюю стосовно класів В и Х, то для доступу до елементів класів вона вимагає посилання на об'єкт objх класу Х

int Efunc(X& objх); //

Функція Efunc( ) може використовувати перемінні і функції-члени класу Х тільки з атрибутом public, наприклад: objх.m, objх.e і objх.Xfunc( ).

Конструктори базового класу повинні оголошуватися у розділах public чи protected. Причому, конструктори похідних класів обов'язково викликають конструктори базових класів.

Приклади:

class base1

{

int x; // private

public:

//Конструктор

base1(int i) {x = i;}

};

class base2

{

int x; // private

public:

//Конструктор (інша

//форма запису для х)

base2(int i) : x(i) { }

};

Class Der : public base1,

public base2

{

int a, b; // private

public:

//Конструктор

Der(int i, int j) : base1(i*5),

base2(j+i), a(i) { b = j;}

};

У випадку такої ієрархії класів оголошення Der one(1, 2) приведе до ініціалізації конструктором даних-членів об’єкту one: base1::х значенням 5, base2::х значенням 3, Der::a =1, Der::b =2. Форми запису при ініціалізації можуть комбінуватися одна з другою (чергуватися).

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

Конструктори базових класів викликаються перед конструюванням будь-яких елементів похідних класів. Значення даних-членів похідного класу не можуть змінюватися і потім впливати на створення базового класу.

Приклад

class base

{

int x;

public:

base(int i) : x(i) { }

};

class derived : base

{

int a;

public:

derived(int i) : a(i*10), base(a) { } // Не можна,

// тому що конструктору base( ) буде

// передане неініціалізоване a

};

При зовнішнім визначенні конструктора derived::derived( ) він також викликає конструктор базового класу

derived::derived(int i) : base( i ) { ... }