MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Pointeri la funcții

Un pointer la funcție (function pointer) stochează adresa unei funcții. Practic, un pointer la funcție conține adresa primului byte din memorie unde este plasat codul executabil al funcției.

Cel mai frecvent pointer la o funcție este chiar numele funcției. Cu ajutorul numelui funcției putem să o apelăm și să obținem rezultatul acesteia.

Însă, putem defini un pointer la funcție și sub forma unei variabile separate, folosind următoarea sintaxă:

tip (*nume_pointer)(tipuri_parametri);
  • tip reprezintă tipul valorii returnate de funcție
  • nume_pointer este un identificator ales conform regulilor de denumire a variabilelor
  • parametri definesc tipurile parametrilor, separate prin virgulă (dacă există)

Un pointer poate indica doar către o funcție care are același tip de returnare și aceiași parametri ca definiția pointerului.

De exemplu, definim un pointer la funcție astfel:

void (*message)();

În acest caz este definit pointerul "message", care poate indica funcții fără parametri și care returnează "void" (adică nimic).

#include <iostream>
 
void hello();
void goodbye();
  
int main()
{
    void (*message)();  // definirea pointerului la funcție
      
    message = hello;
    message();
    message = goodbye;
    message();
}
void hello()
{
    std::cout << "Hello, World" << std::endl;
}
void goodbye()
{
    std::cout << "Good Bye, World" << std::endl;
}

Unui pointer i se poate atribui o funcție care corespunde prin tipul de returnare și specificația parametrilor:

message = hello;

Adică acum pointerul message conține adresa funcției hello. Putem apela funcția astfel:

message();

Alternativ:

(*message)();

Ulterior, putem atribui pointerului adresa altei funcții compatibile. Rezultatul programului:

Hello, World  
Good Bye, World

Atenție la paranteze în definirea pointerului, Definiția: void (*message)();

NU este echivalentă cu:

void *message();

În a doua variantă este definit un prototip de funcție message care returnează un pointer de tip void*, nu un pointer la funcție.

Definirea și inițializarea pointerului

Pointerul poate fi inițializat direct:

void (*message)() {hello}; // indică către funcția hello
// sau
void (*message2)() = hello;

Se poate inițializa cu nullptr:

void (*message)() { nullptr };

Dacă pointerul este inițializat cu o funcție, putem folosi auto:

auto message { hello };
auto message2 = hello;

Pentru claritate, putem adăuga * după auto:

auto* message { hello };

Dar, practic, cu sau fără *, nu face diferență.

Se poate folosi și operatorul &:

auto message { &hello };

Dar utilizarea & sau * cu auto nu afectează comportamentul.

Pointer la funcție cu parametri

#include <iostream>
  
int sum(int, int);
int subtract(int, int);
   
int main()
{
    int a{10};
    int b{5};
    int (*operation)(int, int) {sum};   // pointerul operation indică funcția sum
    int result = operation(a, b);
    // sau: result = (*operation)(a, b);
    std::cout << "result = " << result << std::endl;     // result = 15
       
    operation = subtract;   // pointerul operation indică funcția subtract
    result = operation(a, b);
    std::cout << "result = " << result << std::endl;     // result = 5
}
int sum(int x, int y)
{
    return x + y;
}
int subtract(int x, int y)
{
    return x - y;
}

Aici, pointerul operation poate indica funcții care primesc doi parametri int și returnează un int. Putem schimba adresa spre funcții precum sum și subtract și le putem apela prin pointer, trecând valori concrete.

Vectori de pointeri la funcții

Pe lângă pointerii simpli, putem defini și vectori de pointeri la funcții:

tip (*nume_vector[dimensiune])(parametri);

Exemplu:

double (*actions[])(int, int);

"actions" este un vector de pointeri la funcții care primesc doi int și returnează double.

Exemplu aplicat:

#include <iostream>
  
void add(int, int);
void subtract(int, int);
void multiply(int, int);
  
int main()
{
    int a {10};
    int b {5};
    void (*operations[3])(int, int) = {add, subtract, multiply};
       
    unsigned length = std::size(operations);
       
    for(unsigned i{}; i < length; i++)
    {
        operations[i](a, b);    // apelul funcției prin pointer
    }
}
void add(int x, int y)
{
    std::cout << "x + y = " << x + y << std::endl;
}
void subtract(int x, int y)
{
    std::cout << "x - y = " << x - y << std::endl;
}
void multiply(int x, int y)
{
    std::cout << "x * y = " << x * y << std::endl;
}

Aici, vectorul operations conține trei funcții: add, subtract, multiply, care sunt apelate în buclă în main().

Rezultatul afișat în consolă:

x + y = 15  
x - y = 5  
x * y = 50