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

15.3. Використання захищених членів класу

Член класу може бути оголошений не тільки відкритим (public) або закритим (private), але і захищеним (protected). Окрім того, базовий клас у цілому може успадковуватися з використанням специфікатора protected. Ключове слово protected додане мові програмування C++ для надання механізму успадкування більшої гнучкості.

Специфікатор доступу protected оголошує захищені члени або забезпечує успадкування захищеного класу.

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

15.3.1. Використання специфікатора доступу protected для надання членам класу статусу захищеності

Як уже зазначалося вище, закритий член базового класу не доступний ніяким іншим частинам програми, в т.ч. йдеться і похідні класи. Проте із захищеними членами все відбувається інакше. Якщо базовий клас успадковується як public-клас, то захищені члени базового класу стають захищеними членами похідного класу, тобто доступними для нього. Отже, використовуючи специфікатор protected, можна створити члени класу, які закриті у межах свого класу, але можуть успадковувати похідний клас, причому з отриманням доступу до себе. Для розуміння сказаного розглянемо такий приклад програми.

Код програми 15.4. Демонстрація механізму використання захищених членів класу

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

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

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

protected:

int izm, jzm; // Ці члени закриті у класі baseClass

// але доступні для класу derived.

public:

void setBase(int a, int b) { izm = a; jzm = b;}

void showBase()

{ cout << "izm= " << izm << "; jzm= " << jzm << "\n";}

};

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

class derived : public baseClass {

int kzm;

public:

// Клас derived має доступ до членів класу baseClass izm та jzm.

void setKzm() { kzm = izm*jzm;}

void showKzm() { cout << "kzm= " << kzm << "\n";}

};

int main()

{

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

D_ob.setBase(2, 3);// OK, класу derived це робити дозволено.

D_ob.showBase(); // OK, класу derived це робити дозволено.

D_ob.setKzm(); // Функція setKzm() належить класу derived.

D_ob.showKzm(); // Функція showKzm() належить класу derived.

getch(); return 0;

}

Оскільки клас baseClass успадкований класом derived відкритим способом (тобто як public-клас), а члени izm та jzm оголошені захищеними у класі baseClass, то функція setKzm() (член класу derived) може отримувати до них доступ. Якби члени izm та jzm були оголошені у класі baseClass закритими, то клас derived не міг би звертатися до них і ця програма не скомпілювалася б.

Необхідно пам'ятати! Специфікатор protected дає змогу створити член класу, який буде доступним у рамках даної ієрархії класів, але є закритим для решти елементів програми.

Якщо деякий похідний клас використовується як базовий для іншого похідного класу, то будь-який захищений член початкового базового класу, який успадковується (відкритим способом) першим похідним класом, може успадковуватися ще раз (як захищений член) другим похідним класом. Наприклад, у наступній (цілком коректній) програмі клас derivedB має законний доступ до членів izm та jzm.

Код програми 15.5. Демонстрація механізму доступу до захищених членів

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

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

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

protected:

int izm, jzm;

public:

void setBase(int a, int b) { izm = a; jzm = b;}

void showBase()

{ cout << "izm= " << izm << "; jzm= " << jzm << "\n";}

};

// Члени izm та jzm успадковуються як protected-члени.

class derivedA : public baseClass {

int kzm;

public:

void setKzm() { kzm = izm*jzm;} // Правомірний доступ

void showKzm() { cout << "kzm= " << kzm << "\n";}

};

// Члени izm та jzm успадковуються опосередковано через клас derivedA.

class derivedB : public derivedA {

int mzm;

public:

void setMzm() { mzm = izm + jzm;} // правомірний доступ

void showMzm() { cout << "mzm= " << mzm << "\n";}

};

int main()

{

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

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

A_ob.setBase(2, 3);

A_ob.showBase(); // izm= 2; jzm= 3

A_ob.setKzm();

A_ob.showKzm(); // kzm= 6

B_ob.setBase(3, 4);

B_ob.showBase(); // izm= 3; jzm= 4

B_ob.setKzm();

B_ob.setMzm();

B_ob.showKzm(); // kzm= 12

B_ob.showMzm(); // mzm= 7

getch(); return 0;

}

Якщо базовий клас успадковується закритим способом (тобто з використанням специфікатора private), то захищені (derived) члени цього базового класу стають закритими (private) членами похідного класу. Отже, якби у попередньому прикладі клас baseClass успадковувався закритим способом, то всі його члени стали б private-членами класу derivedA, і у цьому випадку вони не були б доступні для класу derivedB1. Ця ситуація продемонстровано у наведеному нижче коді програми, яка через це є некоректною і не скомпілюється. Всі помилки відзначені у коментарях.

Код програми 15.6. Демонстрація некоректного використання закритих членів

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

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

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

protected:

int izm, jzm;

public:

void setBase(int a, int b) { izm = a; jzm = b;}

void showBase()

{ cout << "izm= " << izm << "; jzm= " << jzm << "\n";}

};

// Елементи класу baseClass будуть закриті у межах класу derivedA.

class derivedA : private baseClass {

int kzm;

public:

// Виклики цих функцій цілком законні, оскільки змінні izm та jzm

// є одночасно private-членами класу derivedA.

void setKzm() { kzm = izm*jzm;} // OK

void showKzm() { cout << "kzm= " << kzm << "\n";}

};

// Доступ до членів izm, jzm, setBase() і showBase() не успадковується.

class derivedB : public derivedA {

int mzm;

public:

// Неправильно, оскільки члени izm та jzm закриті у межах

// класу derivedA.

void setMzm() { mzm = izm + jzm;} // помилка

void showMzm() { cout << "mzm= " << mzm << "\n";}

};

int main()

{

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

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

A_ob.setBase(1, 2); // Помилка: не можна викликати функцію setBase()

A_ob.showBase(); // Помилка: не можна викликати функцію showBase()

B_ob.setBase(3, 4); // Помилка: не можна викликати функцію setBase()

B_ob.showBase(); // Помилка: не можна викликати функцію showBase()

getch(); return 0;

}

Незважаючи на те, що клас baseClass успадковується класом derivedA закритим способом, однак клас derivedA має доступ до public- і protected-членів класу baseClass. Однак він не може цей привілей передати далі, тобто вниз за ієрархією класів. Ключове слово protected – це частина мови C++. Воно забезпечує механізм захисту певних елементів класу від модифікації функціями, які не є членами цього класу, але дає змогу передавати їх "за успадкуванням".

Специфікатор protected можна також використовувати стосовно структур. Але його не можна застосовувати до об'єднань, оскільки об'єднання не успадковується іншим класом. Деякі компілятори допускають використання специфікатора protected в оголошенні об'єднання, але, оскільки об'єднання не можуть брати участь в успадкуванні, то у цьому контексті ключове слово protected буде рівносильним ключовому слову private.

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

class ім'я_класу {

private-члени

protected:

protected-члени

public:

public-члени

};

Нагадаємо, що розділ захищених членів є необов'язковим.