Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Не підтверджено.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
3.08 Mб
Скачать

Void showX() {cout« х « endl;}

};

class baseB { // Оголошення базового класу protected: int у; public:

Void showY() {cout« у « endl;}

};

//Успадкування двох базових класів.

// Оголошення похідного класу

class derived: public baseA, public baseB { // Оголошення базового класу public:

void setXY(int c, int d) {x = c; у = d;}

};

Int mainO

{

derived ObjD; // Створення об'єкта класу

ObjD.setXY(10, 20); // Член класу derived ObjD.showXO; // Функція з класу baseA

ObjD.showYO; // Функція з класу baseB

getchO; return 0;

}

Як видно з цього коду програми, щоб забезпечити успадкування декількох базових класів, необхідно через кому перерахувати їх імена у вигляді списку. При цьому потрібно вказати специфікатор доступу для кожного успадкованого базово­го класу.

  1. Особливості використання конструкторів і деструкторів при реалізації механізму успадкування

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

  • коли викликаються конструктори і деструктори базового і похідного класів?

  • як можна передати параметри конструктору базового класу?

Відповіді на ці запитання викладено нижче у цьому підрозділі.

  1. Послідовність виконання конструкторів і деструкторів

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

Код програми 5.9. Демонстрація послідовності виконання конструкторів

#include <vcl> #include <iostream> #include <conio> using namespace std;

і деструкторів

// Для потокового введення-виведення // Для консольного режиму роботи // Використання стандартного простору імен

class baseClass { // Оголошення базового класу public:

baseClass() {cout «"Створення baseClass-об'єкта" « endl;} -baseClassO {cout «"Руйнування baseClass-об'єкта" « endl;}

};

// Оголошення похідного класу class derived: public baseClass { public:

derived() {cout«"Створення derived-об'єкта" « endl;}

-derivedO {cout«"Руйнування derived-об'єкта" « endl;}

};

Int mainO

{

derived ObjD; // Створення об'єкта класу

// Ніяких дій, окрім створення і руйнування об'єкта ObjD.

getchO; return 0;

Як зазначено у коментарях для функції mainO, ця програма тільки створює і відразу руйнує об'єкт ObjD, який має тип derived. Внаслідок виконання ця програма відображає на екрані такі результати:

Створення baseClass-об'єкта.

Створення derived-об'єкга.

Руйнування derived-об'єкга.

Руйнування baseClass-об'єкта.

Аналізуючи отримані результати, бачимо, що спочатку виконується констру­ктор класу baseClass, а за ним - конструктор класу derived. Потім (через негайне руйнування об'єкта ObjD у цьому коді програми) викликається деструктор класу de­rived, а за ним - деструктор класу baseClass.

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

Конструктори викликаються у порядку походження класів, а дес­труктори — у зворотному порядку.

Цілком логічно, що функції конструкторів виконуються у порядку походжен­ня їх класів. Оскільки базовий клас "нічого не знає" ні про який похідний клас, операції з ініціалізації, які йому потрібно виконати, не залежать від операцій ініці­алізації, що виконуються похідним класом, але, можливо, створюють попередні умови для подальшої роботи. Тому конструктор базового класу повинен викону­ватися першим.

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

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

Код програми 5.10. Демонстрація послідовності виконання конструкторів і дес­трукторів при розширеній ієрархії класів

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

class baseClass { // Оголошення базового класу public:

baseClassO {cout«"Створення baseClass-об'єкта" « endl;}

-baseClassO {cout«"Руйнування baseClass-об'єкта" « endl;}

};

// Оголошення похідного класу class derivedA: public baseClass { public:

derivedAO {cout«"Створення derivedA-об'єкта" « endl;}

~derivedA() {cout«"Руйнування derivedA-об'єкта"« endl;}

};

// Оголошення похідного класу class derivedB : public derivedA { public:

derivedBO {cout«"Створення derivedB-об'єкта" « endl;}

~derivedB() {cout«"Руйнування derivedB-об'єкта"« endl;}

};