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

Розділ 2. Класи і підкласи

2.1. Конструктор копіювання

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

T::T(const Т&) { ... / * Тіло конструктора*/ }

де Т – ім’я класу.

Цей конструктор викликається в тих випадках, коли новий об'єкт створюється шляхом копіювання існуючого об’єкту:

  • при описі нового об'єкту з ініціалізацією іншим об'єктом;

  • при передачі об'єкту у функцію за значенням;

  • при поверненні об'єкту з функції.

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

Запишемо конструктор копіювання для класу monstr. Оскільки в ньому є поле name, що містить вказівку на рядок символів, конструктор копіювання повинен виділяти пам'ять під новий рядок і копіювати в неї початкову:

monstr::monstr(const monstr &M)

{

if (M.name)

{

name = new char [strlen(M.name) + 1];

strcpy(name, M.name);

}

else name = 0;

health = M.health; ammo = M.ammo; skin = M.skin;

}

monstr Vasia (blue);

monstr Super = Vasia; //Працює конструктор копіювання

monstr *m = new monstr ("Ork");

monstr Green = *m; // Працює конструктор копіювання

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

Правила написання конструкторів класів, що входять в ієрархію, описані в розділі 3 "Спадкування класів".

2.2 Вкладені класи

Клас, оголошений усередині іншого класу, називається вкладеним. Він є членом охоплюючого класу, і його визначення може бути відкрите (public) або закрите (private). Рівень вкладеності не обмежується.

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

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

class External

{

// Inner доступна приватна частина External

friend class Inner;

class Inner // вкладений клас

{

// External доступна приватна частина Inner

friend class External;

};

};

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

Void External::Inner::MethodInner(const External &t)

{

//...

// виклик методу охоплюючого класу

memInner = t.MethodExternal();

//...

}

Метод вкладеного класу MethodInner() отримує посилання на об'єкт зовнішнього класу і звичайним способом викликає метод MethodExternal().

Якщо вкладений клас оголошений як public, то його можна використовувати як тип за всією програмою. Його ім'я слід писати з префіксом – ім'ям охоплюючого класу:

External::Inner *pointer;

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

class External

{

//...

// Inner доступна приватна частина External

friend class Inner;

structure Inner

{ /* всі елементи доступні в External */ };

//...

};

Усередині методів вкладеного класу ключове слово this є вказівкою на поточний об'єкт вкладеного класу.

Методи вкладеного класу можна реалізувати безпосередньо усередині класу. Якщо ж методи вкладеного класу визначаються поза класом, визначення необхідно ставити поза самим зовнішнім з охоплюючих класів – в області глобальної видимості. Ім'я методу у такому разі повинне мати префікси; кількість префіксів дорівнює рівню вкладеності класів.

В області глобальної видимості поза охоплюючим класом можна визначити і сам вкладений клас. C++ вирішує це робити, якщо в охоплюючому класі задати оголошення класу, наприклад:

class A

{

//...

class В; // оголошення вкладеного класу

//...

};

class A::B // зовнішнє визначення вкладеного класу

{

//...

};

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