В С++ помимо обычных указателей есть также указатели на функции. Синтаксис их объявления явно выбивается из общей картины. Допустим, у нас есть простенькая функция, что считает сумму двух чисел.
int intSum(int a, int b)
{
return a + b;
}
Чтобы объявить указатель на функцию с таким прототипом, надо написать следующее:
int main()
{
int (*sumPtr)(int, int);
return 0;
}
Как я уже говорил, синтаксис слегка удивляет. Первое упоминание int - тип возвращаемого значения функции. Далее круглые скобки и звездочка. Это надо просто запомнить. "sumPtr" является именем самого указателя. Последующие круглые скобки с перечнем типов - типы параметров. Объявлю еще один указатель по аналогии для закрепления материала:
#include <iostream>
int intSum(int a, int b)
{
return a + b;
}
void printString(const char* str)
{
std::cout << str;
}
int main()
{
int (*sumPtr)(int, int);
void (*printPtr)(const char*);
return 0;
}
Указатели объявлены, что дальше? Как и любые локальные переменные, "sumPtr" и "printPtr" будут содержать мусор. Поэтому, сделаем так, чтобы эти указатели указывали на соответствующие функции. Небольшое замечание: имя функции и есть ее адресом. Поэтому, конструкция "sumPtr = intSum" может быть заменена на "sumPtr = &intSum"(опционально).
int main()
{
int (*sumPtr)(int, int);
sumPtr = intSum; // sumPtr = &intSum;
void (*printPtr)(const char*);
printPtr = printString; // printPtr = &printString;
return 0;
}
Готово. Теперь немного сюрпризов от С++. Так тоже можно:
int main()
{
int (*sumPtr)(int, int) = intSum;
void (*printPtr)(const char*) = printString;
return 0;
}
Итак, есть два указателя, что указывают на функции. Вызвать функцию через указатель так же легко, как и непосредственно через ее имя.
int main()
{
int (*sumPtr)(int, int) = intSum;
intSum(2, 2); // direct call
sumPtr(2, 2); // call via pointer
void (*printPtr)(const char*) = printString;
printString("Hello, World!"); // direct call
printPtr("Hello, World!"); // call via pointer
return 0;
}
Догадаться, как объявить массив указателей на функции интуитивно сложно. Поэтому, покажу пример. Объявляю массив указателей "sumPtrArray" на функции из десяти элементов. Нулевому указателю присваиваю адрес функции "intSum". Вызываю функцию "intSum" через указатель, что находится в нулевой ячейке массива.
int main()
{
int (*sumPtrArray[10])(int, int);
sumPtrArray[0] = intSum;
sumPtrArray[0](2, 2);
return 0;
}
Если Вы испытали синтаксический шок, у меня есть чем порадовать Вас. Чтобы объявление такого указателя или их массива было так же легко и красиво, как в случае с переменными и массивами примитивных типов, воспользуйтесь typedef:
typedef int (*sumPtr_t)(int, int);
typedef void (*printPtr_t)(const char*);
Я ввел два псевдонима "sumPtr_t" и "printPtr_t" для типов указателей на функции. Теперь их можно использовать как привычные Вам примитивные типы:
void callViaPointers(sumPtr_t sumPtr, printPtr_t printPtr)
{
sumPtr(2, 2);
printPtr("Hello, World!");
}
int main()
{
sumPtr_t sumPtr = intSum;
sumPtr(2, 2);
printPtr_t printPtr = printString;
printPtr("Hello, World!");
callViaPointers(sumPtr, printPtr);
return 0;
}
int intSum(int a, int b)
{
return a + b;
}
Чтобы объявить указатель на функцию с таким прототипом, надо написать следующее:
int main()
{
int (*sumPtr)(int, int);
return 0;
}
Как я уже говорил, синтаксис слегка удивляет. Первое упоминание int - тип возвращаемого значения функции. Далее круглые скобки и звездочка. Это надо просто запомнить. "sumPtr" является именем самого указателя. Последующие круглые скобки с перечнем типов - типы параметров. Объявлю еще один указатель по аналогии для закрепления материала:
#include <iostream>
int intSum(int a, int b)
{
return a + b;
}
void printString(const char* str)
{
std::cout << str;
}
int main()
{
int (*sumPtr)(int, int);
void (*printPtr)(const char*);
return 0;
}
Указатели объявлены, что дальше? Как и любые локальные переменные, "sumPtr" и "printPtr" будут содержать мусор. Поэтому, сделаем так, чтобы эти указатели указывали на соответствующие функции. Небольшое замечание: имя функции и есть ее адресом. Поэтому, конструкция "sumPtr = intSum" может быть заменена на "sumPtr = &intSum"(опционально).
int main()
{
int (*sumPtr)(int, int);
sumPtr = intSum; // sumPtr = &intSum;
void (*printPtr)(const char*);
printPtr = printString; // printPtr = &printString;
return 0;
}
Готово. Теперь немного сюрпризов от С++. Так тоже можно:
int main()
{
int (*sumPtr)(int, int) = intSum;
void (*printPtr)(const char*) = printString;
return 0;
}
Итак, есть два указателя, что указывают на функции. Вызвать функцию через указатель так же легко, как и непосредственно через ее имя.
int main()
{
int (*sumPtr)(int, int) = intSum;
intSum(2, 2); // direct call
sumPtr(2, 2); // call via pointer
void (*printPtr)(const char*) = printString;
printString("Hello, World!"); // direct call
printPtr("Hello, World!"); // call via pointer
return 0;
}
Догадаться, как объявить массив указателей на функции интуитивно сложно. Поэтому, покажу пример. Объявляю массив указателей "sumPtrArray" на функции из десяти элементов. Нулевому указателю присваиваю адрес функции "intSum". Вызываю функцию "intSum" через указатель, что находится в нулевой ячейке массива.
int main()
{
int (*sumPtrArray[10])(int, int);
sumPtrArray[0] = intSum;
sumPtrArray[0](2, 2);
return 0;
}
Если Вы испытали синтаксический шок, у меня есть чем порадовать Вас. Чтобы объявление такого указателя или их массива было так же легко и красиво, как в случае с переменными и массивами примитивных типов, воспользуйтесь typedef:
typedef int (*sumPtr_t)(int, int);
typedef void (*printPtr_t)(const char*);
Я ввел два псевдонима "sumPtr_t" и "printPtr_t" для типов указателей на функции. Теперь их можно использовать как привычные Вам примитивные типы:
void callViaPointers(sumPtr_t sumPtr, printPtr_t printPtr)
{
sumPtr(2, 2);
printPtr("Hello, World!");
}
int main()
{
sumPtr_t sumPtr = intSum;
sumPtr(2, 2);
printPtr_t printPtr = printString;
printPtr("Hello, World!");
callViaPointers(sumPtr, printPtr);
return 0;
}
Если тема показалась сложной, почитайте об указателях на функции-члены.
Комментариев нет:
Отправить комментарий