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

21.2. Застосування покажчиків на функції

Покажчик на функцію – це достатньо складний, але дуже могутній засіб C++-програ­му­вання. Незважаючи на те, що функція не є змінною, проте вона займає фізи|чну| область пам'яті, певну адресу якої можна присвоїти покажчику. Адреса, що присвоюється покажчику, є вхідною точкою функції1. Якщо деякий покажчик посилається на функцію, то її (функцію) можна викликати за допомогою цього покажчика.

Покажчик на функцію посилається на вхідну точку цієї функції.

Покажчики на функції також дають змогу передавати функції як аргументи іншим функціям. Адресу функції можна отримати, використовуючи ім'я функції без круглих дужок і аргументів1. Якщо присвоїти адресу функції покажчику, то цю функцію можна викликати через покажчик. Щоб зрозуміти сказане, розглянемо наведену нижче програму. Вона містить дві функції – vLine() і hLine(), які малюють на екрані вертикальні та горизонтальні лінії заданої довжини.

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

#include <vcl>

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

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

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

void vLine(int i), hLine(int i);

int main()

{

void (*p)(int i);

p = vLine; // Покажчик на функцію vLine()

(*p)(4); // Виклик функції vLine()

p = hLine; // Покажчик на функцію hLine()

(*p)(5); // Виклик функції hLine()

getch(); return 0;

}

void hLine(int i)

{

for(; i; i--) cout << "-";

cout << "\n";

}

void vLine(int i)

{

for(; i; i--) cout << "|\n";

}

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

|

|

|

|

–––––

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

У наступному рядку покажчику р присвоюється адреса функції vLine(). Потім виконується виклик функції vLine() з аргументом 4. Після цього покажчику р присвоюється адреса функції hLine(), і за допомогою цього покажчика реалізується її виклик. У цій програмі під час виклику функцій за допомогою покажчика використовується такий формат:

(*р)(4);

Проте функцію, яка адресується покажчиком р, можна викликати з використанням дещо простішого синтаксису:

р(4);

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

21.2.1. Передача покажчиком на функцію її адреси іншій функції

Незважаючи на те, що у попередньому прикладі покажчик на функцію використано тільки заради ілюстрації, часто таке його застосування має дуже важливе значення. Покажчик на функцію дає змогу передавати її адресу іншій функції. Як показовий приклад можна навести функцію qsort() із стандартної С++-бібліотеки. Функція qsort() – це функція швидкого сортування, що базується на алгоритмі Quicksort, який упорядковує вміст масиву. Ось як виглядає її прототип:

void qsort(void *start, size_t length size_t size,

int (*compare) (const void *, const void *));

Функція qsort() – це функція сортування із стандартної С++-бібліотеки.

Прототип функції qsort() "прописаний" у заголовку <cstdlib>, у якому також визначено тип size_t (як тип unsigned int). Щоб використовувати функцію qsort(), необхідно передати їй покажчик на початок масиву об'єктів, який Ви хочете відсортувати (параметр start), довжину цього масиву (параметр length), розмір у байтах кожного елемента (параметр size) і покажчик на функцію порівняння елементів масиву (параметр * compare).

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

Щоби зрозуміти, як можна використовувати функцію qsort(), розглянемо наведену нижче програму.

Код програми 21.6. Демонстрація механізму використання бібліотечної функції qsort() для сортування елементів текстового масиву

#include <vcl>

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

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

#include <cstdlib> // Для використання бібліотечних функцій

#include <cstring> // Для роботи з рядковими типами даних

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

int Сomp(const void *a, const void *b);

int main()

{

char str[] = "Покажчики на функції дають гнучкість.";

qsort(str, strlen(str), 1, Сomp);

cout << "Відсортований рядок: " << str;

cout << endl;

getch(); return 0;

}

int Сomp(const void *a, const void *b)

{

return * (char *) a – * (char *) b;

}

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

Відсортований рядок: .Пааагджииііїккккннносттууфцччьью

Ця програма сортує рядок str у зростаючому порядку. Оскільки функції qsort() передається вся необхідна їй інформація, в т.ч. покажчик на функцію порівняння, то її можна використовувати для сортування даних будь-якого типу. Наприклад, наведений нижче код програми сортує масив цілих чисел. Для гарантії переносності під час визначення розміру цілочисельного значення в ній використовують оператор sizeof.

Код програми 21.7. Демонстрація механізму використання бібліотечної функції qsort() для сортування елементів цілочисельного масиву

#include <vcl>

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

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

#include <cstdlib> // Для використання бібліотечних функцій

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

int Сomp(const void *a, const void *b);

int main()

{

int num[] = {10, 4, 3, 6, 5, 7, 8};

int i;

qsort(num, 7, sizeof(int), Сomp);

for(i=0; i<7; i++)

cout << num[i]<< " ";

cout << endl;

getch(); return 0;

}

int Сomp(const void *a, const void *b)

{

return * (char *) a – * (char *) b;

}

Не станемо заперечувати, що покажчики на функції є не простими для розуміння, але практика їх використання допоможе і "з ними знайти порозуміння". Відносно покажчиків на функції необхідно розглянути ще один аспект, що є пов'язаним з перевантаженими функціями.