Pointeri la funcții ca parametri
Un pointer la funcție reprezintă, de fapt, un anumit tip, iar o funcție poate avea și un parametru care reprezintă un pointer la funcție. Astfel, putem transmite o funcție altei funcții prin intermediul unui parametru. Cu alte cuvinte, o funcție poate fi argumentul altei funcții.
Să analizăm un exemplu:
#include <iostream>
int add(int, int);
int subtract(int, int);
int operation(int(*)(int, int), int, int); // primul parametru – pointer la funcție
int main()
{
int a{10};
int b{6};
int result = operation(add, a, b);
std::cout << "result: " << result << std::endl;
result = operation(subtract, a, b);
std::cout << "result: " << result << std::endl;
}
int add(int x, int y)
{
return x + y;
}
int subtract(int x, int y)
{
return x - y;
}
int operation(int(*op)(int, int), int a, int b)
{
return op(a, b);
}
În acest caz, primul parametru al funcției operation — int (*op)(int, int) — reprezintă un pointer la o funcție care returnează int și primește doi parametri de tip int. Rezultatul funcției este apelul funcției către care pointează pointerul.
Definiției pointerului îi corespund funcțiile add și subtract, astfel încât le putem transmite ca argument la apelul funcției operation: operation(add, a, b);
Rezultatul execuției programului:
result: 16
result: 4
Funcția transmisă altei funcții ca argument se numește funcție de apel invers sau callback. Iar funcția care primește o altă funcție ca argument este o funcție de ordin înalt (higher-order function). Astfel, în exemplul de mai sus, operation este o funcție de ordin înalt, iar add și subtract sunt funcții de tip callback.
Să analizăm un alt exemplu — vom defini o funcție care poate primi ca parametru o condiție și să afișeze toate elementele dintr-un vector care corespund acestei condiții:
#include <iostream>
// funcții care definesc condiții
bool isEven(int); // dacă numărul este par
bool isPositive(int); // dacă numărul este pozitiv
// Funcție care determină elementele din vector ce îndeplinesc o condiție
// primește o funcție-condiție - bool(*)(int)
// vector de int - int[]
// dimensiune vector - unsigned
void action(bool(*)(int), int[], unsigned);
int main()
{
int numbers[]{ -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 };
const unsigned n { std::size(numbers) }; // obținem dimensiunea vectorului
std::cout << "Even numbers: " << std::endl;
action(isEven, numbers, n); // căutăm numerele pare
std::cout << "\nPositive numbers: " << std::endl;
action(isPositive, numbers, n); // căutăm numerele pozitive
}
bool isEven(int x)
{
return x % 2 == 0;
}
bool isPositive(int x)
{
return x > 0;
}
void action(bool(*condition)(int), int numbers[], unsigned n)
{
// parcurgem vectorul
for (unsigned i{}; i < n; i++)
{
// dacă numbers[i] îndeplinește condiția
if (condition(numbers[i]))
{
std::cout << numbers[i] << "\t";
}
}
std::cout << std::endl;
}
În acest caz, primul parametru al funcției operation — int (*op)(int, int) — reprezintă un pointer la o funcție care returnează int și primește doi parametri de tip int. Rezultatul funcției este apelul funcției către care pointează pointerul.
Definiției pointerului îi corespund funcțiile add și subtract, astfel încât le putem transmite ca argument la apelul funcției operation: operation(add, a, b);
Rezultatul execuției programului:
result: 16
result: 4
Funcția transmisă altei funcții ca argument se numește funcție de apel invers sau callback. Iar funcția care primește o altă funcție ca argument este o funcție de ordin înalt (higher-order function). Astfel, în exemplul de mai sus, operation este o funcție de ordin înalt, iar add și subtract sunt funcții de tip callback.
Să analizăm un alt exemplu — vom defini o funcție care poate primi ca parametru o condiție și să afișeze toate elementele dintr-un vector care corespund acestei condiții:
#include <iostream>
// funcții care definesc condiții
bool isEven(int); // dacă numărul este par
bool isPositive(int); // dacă numărul este pozitiv
// Funcție care determină elementele din vector ce îndeplinesc o condiție
// primește o funcție-condiție - bool(*)(int)
// vector de int - int[]
// dimensiune vector - unsigned
void action(bool(*)(int), int[], unsigned);
int main()
{
int numbers[]{ -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 };
const unsigned n { std::size(numbers) }; // obținem dimensiunea vectorului
std::cout << "Even numbers: " << std::endl;
action(isEven, numbers, n); // căutăm numerele pare
std::cout << "\nPositive numbers: " << std::endl;
action(isPositive, numbers, n); // căutăm numerele pozitive
}
bool isEven(int x)
{
return x % 2 == 0;
}
bool isPositive(int x)
{
return x > 0;
}
void action(bool(*condition)(int), int numbers[], unsigned n)
{
// parcurgem vectorul
for (unsigned i{}; i < n; i++)
{
// dacă numbers[i] îndeplinește condiția
if (condition(numbers[i]))
{
std::cout << numbers[i] << "\t";
}
}
std::cout << std::endl;
}
Funcția action primește ca prim parametru o funcție care definește o condiție la care trebuie să corespundă elementele vectorului. Această condiție este reprezentată prin pointerul bool (*condition)(int). Adică, o funcție care primește un int și returnează bool: true dacă valoarea corespunde condiției, false dacă nu.
În acest program, condițiile sunt reprezentate de două funcții:
- isEven() returnează true dacă numărul este par
- isPositive() returnează true dacă numărul este pozitiv
Al doilea parametru al funcției action este vectorul de numere, iar al treilea este dimensiunea acestuia. Dacă un element îndeplinește condiția, este afișat în consolă.
void action(bool(*condition)(int), int numbers[], unsigned n)
La apelul funcției action() putem transmite condiția dorită:
action(isEven, numbers, n);
action(isPositive, numbers, n);
Rezultatul afișat în consolă:
Even numbers:
-4 -2 0 2 4
Positive numbers:
1 2 3 4 5