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

13.7.1. Використання конструктора копії для ініціалізації одного об'єкта іншим

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

Код програми 13.13. Демонстрація виклику конструктора копії для ініціалізації одного об'єкта іншим

#include <vcl>

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

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

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

class myClass { // Оголошення класового типу

int *p;

public:

myClass(int izm); // Оголошення звичайного конструктора

myClass(const myClass &p_ob); // Оголошення конструктора копії

~myClass();

int getVal() { return *p;}

};

// Визначення звичайного конструктора.

myClass::myClass(int izm)

{

cout << "Виділення p-пам'яті звичайним конструктором.\n";

p = new int;

*p = izm;

}

// Визначення конструктора копії.

myClass::myClass(const myClass &p_ob)

{

p = new int;

*p = *p_ob.p; // Значення копії

cout << "Виділення p-пам'яті конструктором копії.\n";

}

myClass::~myClass()

{

cout << "Звільнення p-пам'яті.\n";

delete p;

}

int main()

{

myClass A_ob(10); // Викликається звичайний конструктор.

myClass B_ob = A_ob; // Викликається конструктор копії.

getch(); return 0;

}

Результати виконання цієї програми є такі:

Виділення p-пам'яті звичайним конструктором.

Виділення p-пам'яті конструктором копії.

Звільнення p-пам'яті.

Звільнення p-пам'яті.

Як підтверджують результати виконання цієї програми, під час створення об'єкта A_ob викликається звичайний конструктор. Але коли об'єкт A_ob використовують для ініціалізації членів-даних об'єкта B_ob, викликається конструктор копії. Використання конструктора копії гарантує, що об'єкт B_ob виділить для своїх членів-даних власну область пам'яті. Без конструктора копії об'єкт B_ob просто був би точною копією об'єкта A_ob, а член A_ob.р указував би на ту ж саму область пам'яті, що і член B_ob.р.

Потрібно мати на увазі, що конструктор копії викликається тільки у разі виконання ініціалізації. Наприклад, така послідовність настанов не викличе конструктора копії, визначеного у попередній програмі:

myClass A_ob(2), B_ob(3);

//...

B_ob = A_ob;

У цьому записі настанова B_ob = A_ob виконує операцію присвоєння, а не операцію копіювання.

13.7.2. Використання конструктора копії для передачі об'єкта функції

Під час передачі об'єкта функції як аргумент створюється копія цього об'єкта. Якщо у класі визначено конструктор копії, то саме він і викликається для створення копії. Розглянемо програму, у якій використовується конструктор копії для належного оброблення об'єктів типу myClass під час їх передачі функції як аргументів. Нижче наведемо коректну версію некоректної програми, представленої у розд. 13.5.2.

Код програми 13.14. Демонстрація механізму використання конструктора копії для передачі об'єкта функуції

#include <vcl>

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

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

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

class myClass { // Оголошення класового типу

int *p;

public:

myClass(int izm); // Оголошення звичайного конструктора

myClass(const myClass &p_ob); // Оголошення конструктора копії

~myClass();

int getVal() { return *p;}

};

// Визначення звичайного конструктора

myClass::myClass(int izm)

{

cout << "Виділення пам'яті, яка адресується покажчиком p.\n";

p = new int;

*p = izm;

}

// Визначення конструктора копії.

myClass::myClass(const myClass &p_ob)

{

p = new int;

*p = *p_ob.p; // значення копії

cout << "Викликаний конструктор копії.\n";

}

myClass::~myClass()

{

cout << "Звільнення пам'яті, яка адресується покажчиком p.\n";

delete p;

}

// Ця функція приймає один об'єкт-параметр.

void display(myClass a_ob)

{

cout << "*p= " << a_ob.getVal() << "\n";

}

int main()

{

myClass A_ob(10); // Створення об'єкта класу

display(A_ob);

getch(); return 0;

}

Внаслідок виконання цієї програми на моніторі буде відображено такі результати:

Виділення пам'яті, яка адресується покажчиком p.

Викликаний конструктор копії.

*p= 10

Звільнення пам'яті, яка адресується покажчиком p.

Звільнення пам'яті, яка адресується покажчиком p.

У процесі виконання цієї програми тут відбувається таке: коли у функції main() створюється об'єкт A_ob, "стараннями" звичайного конструктора виділяється пам'ять, і адреса цієї області пам'яті присвоюється покажчику A_ob.р. Потім об'єкт A_ob передається функції display(), а саме – її параметру a_ob. У цьому випадку викликається конструктор копії, який для об'єкта A_ob створює копію з іменем a_ob. Конструктор копії виділяє пам'ять для цієї копії, а значення покажчика на виділену область пам'яті присвоює члену р об'єкта-копії. Потім значення, яка адресується покажчиком р початкового об'єкта, записується в область пам'яті, адреса якої зберігається в покажчику р об'єкта-копії. Таким чином, області пам'яті, що адресуються покажчиками A_ob.р і p_ob.р, роздільні та незалежні одна від одної, але значення (на які вказують A_ob.р і p_ob.р), що зберігаються в них, однакові. Якби конструктор копії не був визначений, то внаслідок створення за замовчуванням побітової копії члени A_ob.р і p_ob.р указували б на одну і ту саму область пам'яті.

Після завершення роботи функції display() об'єкт p_ob виходить з області видимості. Цей вихід супроводжується викликом його деструктора, який звільняє область пам'яті, яка адресується покажчиком p_ob.p. Нарешті, після завершення роботи функції main() виходить з області видимості об'єкт A_ob, що також супроводжується викликом його деструктора і відповідним звільненням області пам'яті, яка адресується покажчиком A_ob.р. Як бачимо, використання конструктора копії усуває деструктивні побічні ефекти, пов'язані з передачею об'єкта функції.