Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Объявление указателей на функции в C/C++
Указатель на функцию — это переменная, которая хранит адрес функции в памяти. Это мощный инструмент для реализации callback'ов, стратегий и функциональности более высокого порядка.
Базовое объявление указателя на функцию
Синтаксис может быть запутанным, поэтому разберёмся пошагово:
// Обычная функция
int add(int a, int b) {
return a + b;
}
// Указатель на функцию
int (*ptr)(int, int) = &add;
// Вызов через указатель (оба способа работают)
int result1 = ptr(3, 4); // Способ 1
int result2 = (*ptr)(3, 4); // Способ 2 (более явный)
Как читать объявление int (*ptr)(int, int):
ptr— имя переменной(int, int)— параметры функцииint— тип возвращаемого значения*— это указатель
Шаг за шагом: разбор синтаксиса
// Шаг 1: тип возвращаемого значения
int ...
// Шаг 2: это указатель на функцию
int (*ptr)...
// Шаг 3: параметры функции
int (*ptr)(int, int)
// Результат: указатель на функцию, принимающую два int и возвращающую int
Объявление без инициализации
// Только объявление (без инициализации)
int (*operation)(int, int);
// Позже инициализируем
operation = add;
// Вызываем
int result = operation(10, 20);
Void функции
// Указатель на функцию, возвращающую void
void (*print_func)(const char*) = nullptr;
void hello(const char* name) {
std::cout << "Hello, " << name << std::endl;
}
int main() {
print_func = hello;
print_func("World"); // Выведет: Hello, World
}
Массив указателей на функции
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int main() {
// Массив из 3 указателей на функции
int (*operations[3])(int, int) = {
add,
subtract,
multiply
};
std::cout << operations[0](10, 5) << std::endl; // 15 (add)
std::cout << operations[1](10, 5) << std::endl; // 5 (subtract)
std::cout << operations[2](10, 5) << std::endl; // 50 (multiply)
}
Передача указателя на функцию в качестве параметра
// Функция, принимающая указатель на функцию
int apply_operation(int a, int b, int (*op)(int, int)) {
return op(a, b);
}
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int main() {
std::cout << apply_operation(3, 4, add) << std::endl; // 7
std::cout << apply_operation(3, 4, multiply) << std::endl; // 12
}
Возврат указателя на функцию
// Функция, возвращающая указатель на функцию
int (*get_operation(char op))(int, int) {
switch (op) {
case '+':
return add;
case '*':
return multiply;
default:
return add;
}
}
int main() {
auto operation = get_operation('+');
std::cout << operation(3, 4) << std::endl; // 7
}
Примечание: такой синтаксис очень сложен. Лучше использовать using или typedef.
Упрощение синтаксиса через typedef
// Объявляем тип для указателя на функцию
typedef int (*MathOperation)(int, int);
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
int apply(int x, int y, MathOperation op) {
return op(x, y);
}
int main() {
MathOperation ops[2] = {add, multiply};
std::cout << apply(3, 4, ops[0]) << std::endl; // 7
std::cout << apply(3, 4, ops[1]) << std::endl; // 12
}
Современный C++: using вместо typedef
// C++11 и позже (более читаемо)
using MathOperation = int(*)(int, int);
int add(int a, int b) { return a + b; }
int main() {
MathOperation op = add;
std::cout << op(3, 4) << std::endl; // 7
}
Callback функции
Практический пример: регистрация обработчика событий.
class Button {
private:
void (*on_click)() = nullptr;
public:
void set_click_handler(void (*handler)()) {
on_click = handler;
}
void click() {
if (on_click != nullptr) {
on_click();
}
}
};
void handle_click() {
std::cout << "Button clicked!" << std::endl;
}
int main() {
Button btn;
btn.set_click_handler(handle_click);
btn.click(); // Выведет: Button clicked!
}
Указатели на методы класса
class Calculator {
public:
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
};
int main() {
// Указатель на метод класса (синтаксис ещё сложнее!)
int (Calculator::*method_ptr)(int, int) = &Calculator::add;
Calculator calc;
// Вызов через указатель
std::cout << (calc.*method_ptr)(3, 4) << std::endl; // 7
// Через указатель на объект
Calculator* calc_ptr = &calc;
std::cout << (calc_ptr->*method_ptr)(3, 4) << std::endl; // 7
}
Лямбда функции (современный подход)
В С++11 лямбды часто проще, чем указатели на функции:
int main() {
// Лямбда с автоматическим выводом типа
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << std::endl; // 7
}
Но если нужна именно типизированная переменная, используй std::function:
#include <functional>
std::function<int(int, int)> op = [](int a, int b) { return a + b; };
std::cout << op(3, 4) << std::endl; // 7
std::function: универсальное решение
Вместо сложных указателей на функции используй std::function:
#include <functional>
using Operation = std::function<int(int, int)>;
int add(int a, int b) { return a + b; }
int main() {
Operation op1 = add;
Operation op2 = [](int a, int b) { return a * b; };
Operation op3 = std::bind(std::plus<int>(), std::placeholders::_1, std::placeholders::_2);
std::cout << op1(3, 4) << std::endl; // 7
std::cout << op2(3, 4) << std::endl; // 12
std::cout << op3(3, 4) << std::endl; // 7
}
Сравнение подходов
| Подход | Синтаксис | Гибкость | Производительность |
|---|---|---|---|
| Указатель на функцию | Сложный | Средняя | Отличная |
typedef | Средний | Средняя | Отличная |
| Лямбда | Простой | Высокая | Отличная |
std::function | Простой | Отличная | Хорошая (небольшие накладные расходы) |
Итоговые рекомендации
- Для простых callback'ов: используй лямбды или
std::function - Для производительности критичного кода: указатели на функции
- Для читаемости кода:
usingвместоtypedef - Для гибкости:
std::function(работает с функциями, лямбдами, функторами) - Избегай: сложных синтаксических конструкций с указателями на методы класса