Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
69
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

Void g(void){}//...}

Тут уже функція g() не має доступу до змінних x та y.

Якщо ми хочемо отримати доступ до деяких закритих полів, то можна робити це через функції, описані у відкритому розділі. Аналогічно можемо діяти при визначенні похідних класів. Якщо в класі Base визначені відкриті функції для доступу до закритих полів, то вони успадковуються похідними класами й можуть використовуватися відкритими функціями похідних класів для доступу до відповідних полів (адже в протоколі похідного класу є доступ до відкритої частини будь-якого базового. Зазначимо, що в такій схемі неважливий специфікатор доступу при утворенні похідного класу.)

І ще одна обставина. Припустимо, що, оголошуючи клас B private-похідним від А, ми хочемо залишити відкритими окремі члени класу А. У такому випадку можна використати операцію розширення області видимості:

class A

{

public:

int i;

}

class B: private A

{//...

public:

A::i;};

Тоді змінна i матиме відкритий статус у класі В (ніби вона визначена у відкритому розділі класу В).

7.9.3. Конструктори та деструктори в похідних класах

Як уже зазначалося, похідний клас зазвичай містить конструктор, якщо він визначений i в базовому. Конструктор у похідному класі потрібен принаймні для того, щоб викликати конструктор базового з відповідним параметром. Синтаксично допускається відсутність конструктора в похідному класі, якщо конструктор базового не має параметрів (void-конструктор).

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

Розглянемо базовий клас, оголошений таким чином:

class Base

{private:

char*basep;

public:

Base(const char*s){basep=strdup(s);}

~Base(){delete basep;}

const char*GetStr(void){return basep;}};

Конструктор класу викликає бібліотечну функцію strdup() для створення копії рядкового аргументу у вигляді динамічної змінної з присвоєнням адреси виділеної пам'яті покажчику basep. Деструктор звільняє цей блок пам'яті. При створенні об'єкта типу

Base president("Grushevskiy");

конструктору класу передається рядок "Grushevskiy", при цьому він створює копію рядка та присвоює її адресу члену basep об'єкта president. Коли president виходить з області видимості, деструктор знищує рядок.

Оголосимо похiдний клас:

class Derived: public Base

{private:

char*uppercasep;

public:

Derived(const char*s)

~Derived(){delete uppercasep;}

const char*GetStr(void){return uppercasep;}};

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

Конструктор Derived можна реалізувати так:

Derived()::Derived(const char*s)

:Base()

{uppercasep=strupr(strdup(s));};

Конструктор Derived викликає конструктор Base, що поміщає рядок, на який посилається s, у купу та ініціалізує basep адресою копії цього рядка. Потім конструктор похідного класу створює ще одну копію рядка, перетворюючи її символи на маленькі та присвоюючи uppercase адресу цієї копії.

Якщо ми створюємо об'єкт типу Derived, то при цьому створюються дві копії рядка. Розглянемо приклад:

Derived president("Grushevskiy");

cout<<"original string:<<president.GetStr()<<'\n';

cout<<"uppercase string:<<president.GetStr()<<'\n';

Результат:

original string: Grushevskiy

uppercase string: Grushevskiy

При виході з області видимості C++ автоматично викликає деструктори у зворотному порядку за ієрархією успадкування: від похідного класу до базового. Наприклад, при виході об'єкта класу president з області видимості спочатку викликається деструктор похідного класу, який виконує оператор delete uppercasep, а потім – конструктор базового, що виконує оператор delete basep. На відміну від конструкторів, деструктор похідного класу ніколи не викликає безпосередньо деструктор базового (деструктор класу можна викликати безпосередньо як функцію-член).

Розглянемо ще один приклад:

class base

{public:

base (char*n,shint t);

~base();};

class derived:public base

{base m;

public:

derived (char*n);

~derived();};

derived::derived(char*n):(n,10),m("member",123){

//...}

Бачимо, що параметри конструктора члена класу m указуються при виклику конструктора похідного класу.