Указатели на функции
Указатель на функцию (function pointer) хранит адрес функции. По сути указатель на функцию содержит адрес первого байта в памяти, по которому располагается выполняемый код функции.
Самым распространенным указателем на функцию является ее имя. С помощью имени функции можно вызывать ее и получать результат ее работы.
Но также указатель на функцию мы можем определять в виде отдельной переменной с помощью следующего синтаксиса:
1
тип (*имя_указателя) (параметры);
Здесь тип представляет тип возвращаемого функцией значения.
имя_указателя представляет произвольно выбранный идентификатор в соответствии с правилами о наименовании переменных.
И параметры определяют тип и название параметров через запятую при их наличии.
Например, определим указатель на функцию:
1
void (*message) ();>
В данном случае определен указатель, который имеет имя message. Он может указывать на функции без параметров, которые возвращают тип void (то есть ничего не возвращают).
Используем указатель на функцию:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
void hello();
void goodbye();
int main()
{
void (*message)();
message=hello;
message();
message = goodbye;
message();
return 0;
}
void hello()
{
std::cout << "Hello, World" << std::endl;
}
void goodbye()
{
std::cout << "Good Bye, World" << std::endl;
}
Указателю на функцию можно присвоить функцию, которая соответствует указателю по возвращаемому типу и спецификации параметров:
1
message=hello;
То есть в данном случае указатель message теперь хранит адрес функции hello. И посредством обращения к указателю мы можем вызвать эту функцию:
1
message();
В качестве альтернативы мы можем обращаться к указателю на функцию следующим образом:
1
(*message)();
Впоследствии мы можем присвоит указателю адрес другой функции, как в данном случае. В итоге результатом данной программы будет следующий вывод:
Hello, World
Good Bye, World
При определении указателя стоит обратить внимание на скобки вокруг имени. Так, использованное выше определение
1
void (*message) ();
НЕ будет аналогично следующему определению:
1
void *message ();
Во втором случае определен не указатель на функцию, а прототип функции message, которая возвращает указатель типа void*.
Рассмотрим еще один указатель на функцию:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
int add(int, int);
int subtract(int, int);
int main()
{
int a = 10;
int b = 5;
int result;
int (*operation)(int a, int b);
operation=add;
result = operation(a, b);
// result = (*operation)(a, b); // альтернативный вариант
std::cout << "result=" << result << std::endl; // result=15
operation = subtract;
result = operation(a, b);
std::cout << "result=" << result << std::endl; // result=5
return 0;
}
int add(int x, int y)
{
return x+y;
}
int subtract(int x, int y)
{
return x-y;
}
Здесь определен указатель operation, который может указывать на функцию с двумя параметрами типа int, возвращающую также значение типа int. Соответственно мы можем присвоить указателю адреса функций add и subtract и вызвать их, передав при вызове указателю некоторые значения для параметров.
Массивы указателей на функции
Кроме одиночных указателей на функции мы можем определять их массивы. Для этого используется следующий формальный синтаксис:
1
тип (*имя_массива[размер]) (параметры)
Например:
1
double (*actions[]) (int, int)
Здесь actions представляет массив указателей на функции, каждая из которых обязательно должна принимать два параметра типа int и возвращать значение типа double.
Посмотрим применение массива указателей на функции на примере:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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};
// получаем длину массива
int length = sizeof(operations)/sizeof(operations[0]);
for(int i=0; i < length;i++)
{
operations[i](a, b); // вызов функции по указателю
}
return 0;
}
void add(int x, int y)
{
std::cout << "x + y = " << x + y << std::endl;
}
void subtract(int x, int y)
{
int result = x - y;
std::cout << "x - y = " << x - y << std::endl;
}
void multiply(int x, int y)
{
std::cout << "x * y = " << x * y << std::endl;
}
Здесь массив operations содержит три функции add, subtract и multiply, которые последовательно вызываются в цикле через перебор массива в функции main.
Консольный вывод программы:
x + y = 15
x - y = 5
x * y = 50