При написанні класу з декількома конструкторами, необхідність вказувати значення за замовчуванням всім членам в кожному конструкторі призведе до написання зайвого коду. Якщо ви оновите значення за замовчуванням якогось одного члена, то вам доведеться лізти в кожен конструктор.
Починаючи з C++11, звичайним змінним-членам класу (ті, які не використовують ключове слово static) можна задати значення за замовчуванням напряму — використати ініціалізацію:
1 2 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 |
#include <iostream> class Something { private: double m_length = 3.5; // m_length має значення за замовчуванням 3.5 double m_width = 3.5; // m_width має значення за замовчуванням 3.5 public: Something() { // Цей конструктор використовує вищенаведені значення за замовчуванням, так як тут ці значення не перевизначаються } void print() { std::cout << "length: " << m_length << " and width: " << m_width << '\n'; } }; int main() { Something a; // a.m_length = 3.5, a.m_width = 3.5 a.print(); return 0; } |
Результат виконання програми:
length: 3.5 and width: 3.5
Таким чином, ви надаєте значення за замовчуванням вашим змінним-членам, які будуть використовуватися вашими конструкторами, якщо самі конструктори не нададуть ці значення (через списки ініціалізації членів).
Проте конструктори все ще визначають тип об’єктів, які можуть бути створені, наприклад:
1 2 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 |
#include <iostream> class Something { private: double m_length = 3.5; double m_width = 3.5; public: // Зверніть увагу, тут немає конструктора за замовчуванням Something(double length, double width) : m_length(length), m_width(width) { // m_length і m_width ініціалізуються цим конструктором (вищенаведені значення за замовчуванням не використовуються) } void print() { std::cout << "length: " << m_length << ", width: " << m_width << '\n'; } }; int main() { Something a; // не скомпілюється, так як потрібен конструктор за замовчуванням, навіть якщо члени класу мають значення за замовчуванням return 0; } |
Незважаючи на те, що ми надали значення за замовчуванням всім змінним-членам класу, конструктор за замовчуванням не був наданий, тому ми не можемо створити об’єкт класу Something без параметрів.
Якщо надано значення за замовчуванням, і конструктор ініціалізує член через список ініціалізації членів, то пріоритет буде у списку ініціалізації членів:
1 2 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 |
#include <iostream> class Something { private: double m_length = 3.5; double m_width = 3.5; public: Something(double length, double width) : m_length(length), m_width(width) { // m_length і m_width ініціалізуються конструктором (вищенаведені значення за замовчуванням не використовуються) } void print() { std::cout << "length: " << m_length << " and width: " << m_width << '\n'; } }; int main() { Something a(4.5, 5.5); a.print(); return 0; } |
Результат виконання програми:
length: 4.5 and width: 5.5
Правило: Використовуйте ініціалізацію нестатичних членів для встановлення значень за замовчуванням змінним-членам.
Тест
Завдання №1
Додайте в наступну програму ініціалізацію нестатичних членів і список ініціалізації членів:
1 2 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 |
#include <string> #include <iostream> class Thing { private: std::string m_color; double m_radius; public: // Конструктор за замовчуванням без параметрів Thing() { m_color = "blue"; m_radius = 20.0; } // Конструктор з параметром color (для radius надано значення за замовчуванням) Thing(const std::string &color) { m_color = color; m_radius = 20.0; } // Конструктор з параметром radius (для color надано значення за замовчуванням) Thing(double radius) { m_color = "blue"; m_radius = radius; } // Конструктор з параметрами color і radius Thing(const std::string &color, double radius) { m_color = color; m_radius = radius; } void print() { std::cout << "color: " << m_color << " and radius: " << m_radius << '\n'; } }; int main() { Thing defl; defl.print(); Thing red("red"); red.print(); Thing thirty(30.0); thirty.print(); Thing redThirty("red", 30.0); redThirty.print(); return 0; } |
Результат виконання програми повинен бути наступним:
color: blue and radius: 20
color: red and radius: 20
color: blue and radius: 30
color: red and radius: 30
Відповідь №1
1 2 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 |
#include <iostream> #include <string> class Thing { private: std::string m_color = "blue"; double m_radius = 20.0; public: // Конструктор за замовчуванням без параметрів (color і radius використовують значення за замовчуванням) Thing() { } // Конструктор з параметром color (для radius надано значення за замовчуванням) Thing(const std::string &color): m_color(color) { } // Конструктор з параметром radius (для color надано значення за замовчуванням) Thing(double radius): m_radius(radius) { } // Конструктор з параметрами color і radius Thing(const std::string &color, double radius): m_color(color), m_radius(radius) { } void print() { std::cout << "color: " << m_color << " and radius: " << m_radius << '\n'; } }; int main() { Thing defl; defl.print(); Thing red("red"); red.print(); Thing thirty(30.0); thirty.print(); Thing redThirty("red", 30.0); redThirty.print(); return 0; } |
Завдання №2
Навіщо ми оголосили пустий конструктор за замовчуванням в програмі з завдання №1? Всі ж змінні-члени і так мають значення за замовчуванням.
Відповідь №2
Об’єкт defl
класу Thing буде шукати конструктор за замовчуванням. Якщо його не буде, то компілятор видасть помилку.