Тема 3. Конструктори і деструктори
Зміст теми. Призначення конструкторів та деструкторів. Оголошення конструкторів, деструкторів. Конструктори за замовчанням. Конструктори с параметрами. Конструктори копіювання.
Після створення об'єкта його атрибути можна ініціалізувати (тобто атрибутам задати початкові значення) за допомогою конструктора. Конструктор – це спеціальна функція класу з тим же ім'ям, що і клас, який потім викликається автоматично при створенні екземпляра класу (об'єкта). Дані-члени класу не можуть набувати початкового значення у визначенні класу. Вони або повинні набути цього значення в конструкторі класу, або їх значення можна встановити пізніше, після створення об'єкта. Конструктори не можуть повертати які-небудь значення. Конструктори можна перенавантажувати, щоб забезпечити безліч початкових значень об'єктів класу, тобто клас може мати декілька конструкторів.
Хороший стиль програмування свідчить: завжди передбачайте конструктор для впевненості в тому, що об'єкт набув відповідного значення, що має сенс.
Якщо для класу не визначено ніякого конструктора, компілятор автоматично вбудовує в програму конструктор без параметрів. Такий конструктор називається конструктором за замовчанням. Такий конструктор не задає ніяких початкових значень (дані об'єкта мають випадкові значення, що залишилися в оперативній пам'яті від роботи попередніх програм, тобто «сміття» оперативної пам'яті). Якщо важливо, якими значеннями ініціалізуються поля об'єкта, то слід явно визначити конструктор.
Наприклад, оголосимо клас круг з конструктором без параметрів:
class CKrug
{
int radius;
public:
CKrug (); // оголошення конструктора без параметрів
};
Визначення (опис) конструктора наведено нижче:
CKrug ::CKrug ()
{
radius=0; // тут можна задати будь-яке значення, наприклад 10
}
Радіус круга ініціалізується константним значенням, в даному випадку цілим значенням 0. Об'єкти, які будуть створені за допомогою цього конструктора, завжди матимуть однакові значення (в даному випадку 0). Зручно проводити ініціалізацію об'єкта різними значеннями. Такі значення можна передавати конструктору як аргументи. Отже, додамо в клас CKrug оголошення конструктора з параметром:
class CKrug
{
int radius;
public:
CKrug (); // оголошення конструктора без параметрів
CKrug (int rad); // оголошення конструктора з параметром
};
Визначення (опис) конструктора поза класом:
CKrug ::CKrug (int rad)
{
radius=rad;
}
При оголошенні об'єкта класу, що містить конструктор з параметрами між ім'ям об'єкта і крапкою з комою, можна в дужках вказати список ініціалізації атрибутів (членів-даних). Ці значення передаються в конструктор класу, якими ініціалізуються дані об'єкта цього класу. Наприклад:
CKrug Krug(25);
Після створення об'єкта Krug, радіус матиме значення 25.
Також можливо виконати ініціалізацію об'єкта за допомогою значень полів вже існуючого об'єкта. Для цього не потрібно самим створювати спеціальний конструктор, оскільки такий конструктор надається компілятором для кожного створюваного класу і називається конструктором копіювання за замовчанням. Конструктор копіювання має єдиний аргумент, що є об'єктом того ж класу, що і конструктор.
Приклад використання конструктора копіювання демонструє наступний фрагмент:
CKrug Krug1(40);
CKrug Krug2(Krug1);
Радіус об'єкта Krug1, після його створення, буде мати значення 40. Радіус об'єкта Krug2, також буде мати значення 40, бо його ініціалізація відбулася значенням об'єкта Krug1 за допомогою конструктора копіювання. Тобто, дія конструктора копіювання зводиться до копіювання атрибутів одного об'єкта у відповідні атрибути другого об'єкта.
Якщо в класі оголошено декілька конструкторів, то відбувається виклик того конструктора, у якого кількість і типи аргументів відповідають кількості і типам, вказаним при створенні екземпляра класу (об'єкта).
Деструктор – це також спеціальна функція класу, що використовується для звільнення пам'яті, яку займає об'єкт. Ім'я деструктора співпадає з ім'ям класу, але перед ним ставиться символ тильда (~). Деструктор класу викликається при знищенні об'єкта – наприклад, коли виконувана програма покидає область дії, в якій був створений об'єкт цього класу. Насправді деструктор сам не знищує об'єкт – він виконує підготовку перед тим, як система звільняє область пам'яті, в якій зберігався об'єкт, щоб використовувати її для розміщення нових об'єктів.
Якщо деструктор явним чином не визначений, компілятор автоматично створює порожній деструктор. Описувати в класі деструктор явним чином потрібно у разі, коли об'єкт містить покажчики на пам'ять, що виділяється динамічно – інакше при знищенні об'єкта пам'ять, на яку посилалися його поля-покажчики, не буде помічена як вільна. Деструктор не приймає ніяких параметрів і не повертає ніяких значень. Клас може мати тільки один деструктор – перевантаження деструктора не дозволяється.
Додамо в клас CKrug оголошення деструктора:
class CKrug
{
int radius;
public:
CKrug (); // оголошення конструктора без параметрів
CKrug (int rad); // оголошення конструктора з параметром
~CKrug (); // оголошення деструктора
};
Визначення (опис) деструктора поза класом:
CKrug ::~CKrug ()
{
// код для звільнення динамічної пам'яті
}
Запитання для самоконтролю