Урок №132. Статичні змінні-члени класу

  Юрій  | 

  Оновл. 12 Лют 2021  | 

 17

На цьому уроці ми розглянемо використання статичних змінних-членів класу в мові С++.

Статичні змінні-члени класу

На уроці №54 ми дізналися, що статичні змінні зберігають свої значення і не знищуються навіть після виходу з блоку, в якому вони оголошені, наприклад:

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

1
2
3

Зверніть увагу, s_id зберігає своє значення після кожного виклику функції generateID().

Ключове слово static має інше значення, коли мова йде про глобальні змінні — воно надає їм внутрішній зв’язок (що обмежує їх видимість/використання за межами файлу, в якому вони визначені). Оскільки використання глобальних змінних — це зло, то ключове слово static в цьому контексті використовується не дуже часто.

У мові C++ ключове слово static можна використовувати в класах: статичні змінні-члени і статичні методи. Ми поговоримо про статичні змінні-члени на цьому уроці, а про статичні методи — на наступному.

Перш ніж ми перейдемо до ключового слова static зі змінними-членами класу, давайте спочатку розглянемо наступний клас:

При створенні об’єкта класу, кожен об’єкт отримує свою власну копію всіх змінних-членів класу. В цьому випадку, оскільки ми оголосили два об’єкти класу Anything, у нас буде дві копії m_value: first.m_value і second.m_value. Це різні значення, відповідно, результат виконання програми:

4
3

Змінні-члени класу можна зробити статичними, використовуючи ключове слово static. На відміну від звичайних змінних-членів, статичні змінні-члени є загальними для всіх об’єктів класу. Розглянемо наступну програму:

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

4
4

Оскільки s_value є статичною змінною-членом, то вона є спільною для всіх об’єктів класу Anything. Відповідно, first.s_value — це та ж змінна, що і second.s_value. Вищенаведена програма показує, що до значення, яке ми встановили через перший об’єкт, можна отримати доступ і через другий об’єкт.

Статичні члени не пов’язані з об’єктами класу

Хоча ви можете отримати доступ до статичних членів через різні об’єкти класу (як у вищенаведеному прикладі), але, виявляється, статичні члени існують, навіть якщо об’єкти класу не створені! Подібно глобальним змінним, вони створюються при запуску програми і знищуються, коли програма завершує своє виконання.

Отже, статичні члени належать класу, а не об’єктам цього класу. Оскільки s_value існує незалежно від будь-яких об’єктів класу, то доступ до нього здійснюється напряму через ім’я класу і оператор дозволу області видимості (в даному випадку, через Anything::s_value):

У вищенаведеному фрагменті, доступ до s_value здійснюється через ім’я класу, а не через об’єкт цього класу. Зверніть увагу, ми навіть не створювали об’єкт класу Anything, але ми все одно маємо доступ до Anything::s_value і можемо використовувати цю змінну-член.

Визначення і ініціалізація статичних змінних-членів класу

Коли ми оголошуємо статичну змінну-член всередині тіла класу, ми повідомляємо компілятору про існування статичної змінної-члена, але не про її визначення (аналогією є попереднє оголошення). Оскільки статичні змінні-члени не є частиною окремих об’єктів класу (вони обробляються аналогічно глобальним змінним і ініціалізуються під час запуску програми), то ви повинні явно визначити статичний член поза тілом класу — в глобальній області видимості.

У вищенаведеній програмі це робиться наступним рядком коду:

Тут ми визначили статичну змінну-член класу і ініціалізували її значенням 3. Якщо ж ініціалізатор не надано, то C++ ініціалізує s_value значенням 0.

Зверніть увагу, це визначення статичного члену не підпадає під дію специфікаторів доступу: ви можете визначити і ініціалізувати s_value, навіть якщо він буде private (або protected).

Якщо клас визначено в заголовку, то визначення статичного члена зазвичай поміщається в файл з кодом класу (наприклад, в Anything.cpp). Якщо клас визначено в файлі .cpp, то визначення статичного члена зазвичай пишеться безпосередньо під класом. Не пишіть визначення статичного члена класу в заголовку (подібно глобальним змінним). Якщо цей заголовок підключають більше одного разу, то ви отримаєте кілька визначень одного члена, що призведе до помилки компіляції.

Ініціалізація статичних змінних-членів всередині тіла класу

Є кілька обхідних шляхів визначення статичних членів всередині тіла класу. По-перше, якщо статичний член є константним інтегральним типом (до якого відносяться і char, і bool) або константним перерахуванням, то статичний член може бути ініціалізований всередині тіла класу:

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

По-друге, починаючи з C++11 статичні члени constexpr будь-якого типу даних, що підтримують ініціалізацію constexpr, можуть бути ініціалізовані всередині тіла класу:

Використання статичних змінних-членів класу

Навіщо використовувати статичні змінні-члени всередині класів? Для присвоювання унікального ідентифікатора кожному об’єкту класу (як варіант):

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

1
2
3

Оскільки s_idGenerator є загальним для всіх об’єктів класу Anything, то при створенні нового об’єкта класу Anything конструктор захоплює поточне значення s_idGenerator, а потім збільшує його для наступного об’єкта. Це гарантує унікальність ідентифікаторів для кожного створеного об’єкта класу Anything.

Статичні змінні-члени також можуть бути корисні, коли класу необхідно використовувати внутрішню таблицю пошуку (наприклад, масив, який використовується для зберігання набору попередньо обчислених значень). Роблячи таблицю пошуку статичною, для всіх об’єктів класу створиться тільки одна копія (а не окрема для кожного об’єкта класу). Це допоможе заощадити значну кількість пам’яті.

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (1 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *