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

21.2.2. Пошук адреси перевантаженої функції

Отримати адресу перевантаженої функції трохи складніше, ніж знайти адресу звичайної "одиночної" функції. Якщо ж існує декілька версій перевантаженої функції, то повинен існувати механізм, який би визначав, адресу якої саме її версії ми отримуємо. Під час отримання адреси перевантаженої функції саме спосіб оголошення покажчика визначає, адресу якої її версії буде отримано. По суті, оголошення покажчика у цьому випадку порівнюється з відповідними оголошеннями покажчиків перевантажених функцій. Функція, оголошення якої виявить збіг, і буде тією функцією, адресу якої ми отримали.

У наведеному нижче прикладі коду програми міститься дві версії функції space(). Перша версія виводить на екран count пропусків, а друга – count символів, переданих як аргумент ch. У функції main() оголошуються два покажчики на функції. Перший заданий як покажчик на функцію з одним цілочисельним параметром, а другий – як покажчик на функцію з двома параметрами.

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

#include <vcl>

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

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

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

// Введення на екран count пропусків.

void space(int count)

{

for(; count; count–-) cout << " ";

}

// Введення на екран count символів, переданих в ch.

void space(int count, char ch)

{

for(; count; count-–) cout << ch;

}

int main()

{

// Створення покажчика на void-функцію з одним int-параметром.

void (*fp1)(int);

/* Створення покажчика на void-функцію з одним int-параметром

і одним параметром типу char. */

void (*fp2)(int, char);

fp1 = space; // Отримуємо адресу функції space(int)

fp2 = space; // Отримуємо адресу функції space(int, char)

fp1(22); // Виводимо 22 пропуски (цей виклик є аналогічним

// виклику (*fp1)(22)).

cout << "|\n";

fp2(30, 'x'); // Виводимо 30 символів "x" (цей виклик є

// аналогічним до виклику (*fp2)(30, 'x').

cout << "|\n";

getch(); return 0;

}

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

|

хххххххххххххххххххххххххххххх|

Як зазначено у коментарях до цієї програми, компілятор здатний визначити, адресу якої перевантаженої функції він отримує, на основі того, як оголошено покажчики fp1 і fр2.

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

21.3. Поняття про статичні члени-даних класу

Ключове слово static можна застосовувати і до членів-даних класу. Оголошуючи член-даних класу| статичним, ми тим самим повідомляємо компілятор про те, що, незалежно від того, скільки об'єктів цього класу буде створено, існує тільки одна копія цього static-члена. Іншими словами, static-член розділяється між всіма об'єктами класу. Всі статичні дані під час першого створення об'єкта ініціалізуються нульовими значеннями, якщо перед цим не представлено інших значень ініціалізації.

Один статичний член-даних класу розділяється між всіма об'єктами класу.

Під час оголошення статичного члена-даних у класі програміст не повинен його визначати. Необхідно забезпечити його глобальне визначення поза цим класом. Це реалізується шляхом повторного оголошення цієї статичної змінної за допомогою оператора дозволу області видимості, який дає змогу ідентифікувати, до якого класу вона належить. Тільки у цьому випадку для цієї статичної змінної буде виділено пам'ять.

Розглянемо приклад використання static-члена класу. Вивчіть код цієї програми і постарайтеся зрозуміти, як вона працює.

Код програми 21.9. Демонстрація механізму використання статичних членів-даних класу

#include <vcl>

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

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

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

class ShareVar {

static int num;

public:

void setNum(int izm) { num = izm;}

void showNum() { cout << num << " ";}

};

int ShareVar::num; // Визначаємо static-член num

int main()

{

ShareVar A_ob, B_ob;

A_ob.showNum(); // Виводиться 0

B_ob.showNum(); // Виводиться 0

A_ob.setNum(10); // Встановлюємо static-члена num дорівнює 10

A_ob.showNum(); // Виводиться 10

B_ob.showNum(); // Також виводиться 10

getch(); return 0;

}

Звернемо Вашу увагу на те, що статичний цілочисельний член num оголошений і у класі ShareVar, і його визначено як глобальна змінна. Як було сказано вище, необхідність такого подвійного оголошення зумовлена тим, що під час оголошення члена num у класі ShareVar пам'ять для нього не виділяється. Компілятор C++ ініціалізував змінну num значенням 0, оскільки ніякої іншої ініціалізації у програмі немає. Тому внаслідок двох перших викликів функції showNum() для об'єктів A_ob і B_ob відображається значення 0. Потім об'єкт A_ob встановлює члену num значення, що дорівнює 10, після чого об'єкти A_ob і B_ob знову виводять на екран його значення за допомогою функції showNum(). Але оскільки існує тільки одна копія змінної num, що розділяється об'єктами A_ob і B_ob, то значення 10 буде виведено під час виклику функції showNum() для обох об'єктів.

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

Якщо static-змінна є відкритою (тобто public-змінною), до неї можна звертатися безпосередньо через ім'я її класу, без посилання на будь-який конкретний об'єкт1. Розглянемо, наприклад, таку версію класу ShareVar:

class ShareVar {

public:

static int num;

void setNum(int izm) { num = izm;};

void showNum() { cout << num << " "; }

};

У даній версії змінна num є public-членом даних класу. Це дає змогу нам звертатися до неї безпосередньо, як це показано в такій настанові:

ShareVar::num = 100;

У цьому записі значення змінної num встановлюється незалежно від об'єкта, а для звернення до неї достатньо використовувати ім'я класу і оператора дозволу області видимості. Більше того, ця настанова є правомірною навіть для створення яких-небудь об'єктів типу ShareVar. Таким чином, отримати або встановити значення static-члена класу можна до того, як будуть створені будь-які об'єкти.

І хоча Ви, можливо, поки що не відчули потреби в static-членах класу, проте, у міру набуття досвіду програмування мовою C++, Вам доведеться наштовхнутися на ситуацію, коли вони виявляться дуже корисними, тобто дадуть змогу уникнути застосування глобальних змінних.

Можна також оголосити статичною і функцію-члена класу, але це непоширена практика. До статичної функції-члена класу можуть отримати доступ тільки інші static-члени цього класу2. Статична функція-член не має покажчика this. Створення віртуальних статичних функцій-членів класу не дозволяється. Окрім того, їх не можна оголошувати з модифікаторами const або volatile. Статичну функцію-члена можна викликати для об'єкта її класу або незалежно від будь-якого об'єкта, а для звернення до неї достатньо використовувати ім'я класу і оператор дозволу області видимості.