Указатели на функции
Передавайте функции как аргументы
«Указатели на функции» — бесплатный урок C++ Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.
Что такое указатель на функцию?
Указатель на функцию хранит адрес функции, чтобы Вы могли косвенно вызвать её или передать как данные.
- Тип кодирует сигнатуру.
- Он позволяет функциям принимать поведение в качестве параметра.
#include <iostream>
int add(int a, int b) { return a + b; }
int main() {
int (*op)(int, int) = add;
std::cout << op(3, 4) << '\n';
return 0;
}Объявление типа
Объявление int (*op)(int, int) читается так: op — указатель на функцию, принимающую два целых числа и возвращающую целое число. Круглые скобки вокруг *op обязательны.
#include <iostream>
int square(int x) { return x * x; }
int main() {
int (*fn)(int) = square;
std::cout << fn(5) << '\n';
return 0;
}Вызов через указатель
Вызывайте указатель на функцию так же, как саму функцию. Можно также явно разыменовать его, но это требуется редко.
#include <iostream>
void greet() { std::cout << "Hello\n"; }
int main() {
void (*g)() = greet;
g();
(*g)();
return 0;
}Передача функций в качестве аргументов
Функция может принимать параметр-указатель на функцию, позволяя вызывающему коду подключать собственное поведение.
#include <iostream>
int apply(int x, int (*fn)(int)) { return fn(x); }
int doubler(int n) { return n * 2; }
int main() {
std::cout << apply(10, doubler) << '\n';
return 0;
}Выбор во время выполнения
Поскольку указатель на функцию является переменной, Вы можете решить, какую функцию вызвать, пока программа выполняется.
#include <iostream>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {
bool wantAdd = true;
int (*op)(int, int) = wantAdd ? add : sub;
std::cout << op(8, 3) << '\n';
return 0;
}Массивы указателей на функции
Храните несколько указателей на функции в массиве, чтобы создать простую таблицу диспетчеризации, индексируемую значением.
#include <iostream>
int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
int main() {
int (*ops[2])(int, int) = {add, mul};
std::cout << ops[0](2, 3) << ' ' << ops[1](2, 3) << '\n';
return 0;
}Использование typedef
Синтаксис указателя перегружен. Псевдоним typedef или using присваивает типу понятное имя.
#include <iostream>
using BinOp = int(*)(int, int);
int add(int a, int b) { return a + b; }
int main() {
BinOp op = add;
std::cout << op(6, 7) << '\n';
return 0;
}Указатели на функции и алгоритмы
Стандартные алгоритмы принимают вызываемые объекты, и обычная функция подходит в качестве такого объекта. Здесь предикат подсчитывает четные числа.
#include <iostream>
#include <vector>
#include <algorithm>
bool isEven(int n) { return n % 2 == 0; }
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6};
int c = std::count_if(v.begin(), v.end(), isEven);
std::cout << "Evens: " << c << '\n';
return 0;
}Ограничение: нет состояния
Обычный указатель на функцию не может хранить захваченные данные. Если Вам нужно сохранять контекст между вызовами, используйте глобальные переменные или перейдите к более функциональным вызываемым объектам.
#include <iostream>
int counter = 0;
int next() { return ++counter; }
int main() {
int (*fn)() = next;
std::cout << fn() << ' ' << fn() << ' ' << fn() << '\n';
return 0;
}Преобразование лямбд без захвата
Лямбда, которая ничего не захватывает, может неявно преобразоваться в соответствующий указатель на функцию, что удобно для небольших встроенных функций.
#include <iostream>
int main() {
int (*fn)(int) = [](int x) { return x + 100; };
std::cout << fn(1) << '\n';
return 0;
}Нулевые указатели на функции
Указатель на функцию может иметь значение nullptr, то есть не указывать ни на что. Всегда проверяйте его перед вызовом, чтобы избежать неопределенного поведения.
#include <iostream>
int main() {
int (*fn)(int) = nullptr;
if (fn) {
std::cout << fn(5) << '\n';
} else {
std::cout << "No function set\n";
}
return 0;
}Быстрая проверка
Проверьте своё понимание ограничений указателей на функции.
Повторение
Вы узнали об указателях на функции:
- они хранят адрес функции и вызываются так же, как сама функция
- они позволяют передавать поведение в качестве параметра и создавать таблицы диспетчеризации
- псевдонимы делают их тип понятным
- они не могут хранить состояние, но лямбды без захвата преобразуются в них
Далее Вы познакомитесь с std::function, который может хранить любой вызываемый объект, в том числе объект с состоянием.
Часто задаваемые вопросы
Урок «Указатели на функции» бесплатный?
Да — полный текст урока «Указатели на функции» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.
Чему я научусь в уроке «Указатели на функции»?
Передавайте функции как аргументы Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C++ Academy?
Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Указатели на функции»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C++ Academy?
Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Указатели на функции
- std::function
- std::bind
- Выбор вызываемых объектов