Програмування С, С++теорія та практика (частина 2)
2.5.5 Методи ініціалізації елементів у конструкторах.
Оголошення та використання конструкторів може проходити за одною із наступних схем:
I. Створення об ’єктів з ініціалізацією по замовчуванню.
Конструктор, що оголошується без аргументів, є конструктором по замовчуванню (гіе/аиіі сотігисіог). Якщо він не визначений в описі класу, компілятор створює його по замовчуванню (на практиці він просто виділяє пам’ять при створенні об’єкту свого класу). Як приклад, можна розглянути наступне: с1азз зрЬеге {
риЬ1іс:
£1оа£ г;
£1оа£ х,у,г; зрЬеге()
{
х=1.0; у=2.0;
2=3.0;
г=4 ;
}
};
II. Створення об ’єктів із спеціальною ініціалізацією.
Більшість конструкторів використовуються з аргументами. Адже
не дуже вдалим буде рішення, після того, як створивши порожній об’єкт, потім ще додатково викликати окрему функцію ініціалізації для збереження в ньому певних даних. Наведений нижче код допоможе
ініціалізувати об’єкт саме у момент його створення. Нехай є таке оголошення конструктора у попередньо відомому класі зркеге:
зрЬеге(£1оа£ хсоогй, £1оа£ усоогй, £1оа£ гсоогй,
£1оа£ гайіиз);
Тоді визначення конструктора має бути наступним:
// визначення конструктора
зрЬеге::зрЬеге(£1оа£ хсоогй,£1оа^ усоогй,£1оа£ гсоогй,£1оа^ гайіиз)
{
х=хсоогй; у=усоогй;
2=гсоогй; г=гайіиз;
}
Враховуючи таке оголошення конструктора, необхідно при створенні об’єкту передати йому аргументи, що робить ініціалізацію екземпляру схожим на виклик функції : зрЬеге з(1.0, 2.0, 3.0, 4.0);
Як бачимо у такому разі, змінна визначається та ініціалізується в одному рядку. Для найбільш гнучкої ситуації іноді є сєнс оголосити конструктори з різним типом та кількістю аргументів, що дозволяє будувати більш зрозумілі та пристосовані до користувача класи. Тобто конструктори, як і звичайні функції-елементи, можна перевантажувати. Компілятор, проаналізувавши аргументи при створенні об’єкту, спроможний автоматично визначити, який з конструкторів викликати. При цьому використовуються відомі правила відповідності аргументів при перевантаженні функцій.
Крім того, в Сі++ зустрічаються дві форми ініціалізації з параметрами:
1) ініціалізація у тілі конструктора, відома за вищенаведеними прикладами, схематично представлена як:
с1азз 'Ьмо{ іп£ х,у; риЬ1іс:
£мо(іп£ х1,іп£ у1)
{
х=х1; // присвоєння у тілі конструктора
у=у1;
};
2) ініціалізація списком після заголовку визначення функції:
с1азз опе{ іп£ х,у; риЬ1іс:
опе(іп£ х1,іп£ у1) : х(х1) ,у(у1)
{
}
};
Обидві форми абсолютно рівнозначні, друга, правда, зустрічається дещо рідше.
Ш. Створення об ’єктів шляхом копіювання інших об ’єктів.
У цьому випадку мається на увазі отримання копій вже існуючого об’єкту, що, у свою чергу, потребує особливого конструктора, що носить назву ініціалізатора копії (сору іпіііаіігєг) або конструктор копіювання (сору сотігисіог).
Конструктор копіювання - це спеціальний вид конструктора, який отримує в якості єдиного параметра покажчик на об’єкт цього ж класу. Наступний код демонструє використання такого конструктора:
//визначення конструктора копіювання ехатр1е:: ехатр1е(ехатр1е& ге£егапсе)
{
соип'Ь = ге£егапсе. соипї;
}
Vоій. таіп ()
{
ехатр1е оЬ]ес^(5); //використання конструктора для іпі ехатр1е оЬіес^1=оЬіес^;//використання конструктора // копіювання
//відбувається копіювання між оЬуесІІ та оЬуесІ
}
Конструктори копіювання надзвичайно важливі у випадках, коли потрібно створити копію об’єкту класу. Без них компілятор не спроможний виконати копіювання - все повністю залежить від існуючого конструктора. Копіювання об’єктів відбувається при передачі об’єктів за значенням у функцію або навпаки. Розглянемо приклад, що демонструє передачу об’єктів за значенням:
// функція отримує змінну класу за значенням VОій. £ипс(зогсе оЬ])
{
оЬ].с1азз£ипс(); // виклик компонентної функції класу зогсе }
VОій. таіп ^оігі.)
{
зогсе оЬ] (10) ; // автоматична змінна
£ипс(оЬ]); //передача функції об'єкта за значенням
}
При активації /ипє (оЬ]) компілятор використовує конструктор копіювання для розміщення в стеку копії об’єкту в якості аргументу. Передача за значенням зовсім ще не означатиме, що функція обов’язково отримає точну побайтову копію об’єкту. Адже те, що отримає функція, повністю залежить від того, що підготовлено конструктором копіювання. Подібна до цього ситуація і тоді, коли об’єкт повертається за значенням. (Зауваження: деякі компілятори можуть працювати інакше).
Конструктори у попередніх прикладах з’являлися у секції риЬііс, що зустрічається найчастіше. Проте це зовсім не є обов’язковим. Приватні конструктори не допускають створення об’єктів класу звичайними користувачами та для створення об’єкту вимагають наявності певних умов:
• конструктор може викликатися статичним членом класу;
• конструктор може викликається дружнім класом;
• відповідний об’єкт класу має функцію-елемент, що викликає
конструктор для створення нового об’єкту.
Примітка. Взагалі конструктори не є обов’язковою частиною протокольного опису класу. Якщо ви не визначили ніяких конструкторів, компілятор Сі++ по замовчуванню генерує конструктор "по замовчуванню" (даруйте за каламбур - той, що не має параметрів), який обнуляє усі елементи-дані поточного екземпляру.
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
