Шаг 1.
Указатели на функции

    На этом шаге мы начнем рассматривать описание и использование указателей на функции.

    Прежде чем вводить указатель на функцию, напомним, что каждая функция характеризуется типом возвращаемого значения, именем и сигнатурой. Напомним, что сигнатура определяется количеством, порядком следования и типами параметров. Иногда говорят, что сигнатурой функции называется список типов ее параметров. При использовании имени функции без последующих скобок и параметров имя функции выступает в качестве указателя на эту функцию, и его значением служит адрес размещения функции в памяти. Это значение адреса может быть присвоено другому указателю, и затем уже этот новый указатель можно применять для вызова функции. Однако в определении нового указателя должен быть тот же тип, что и возвращаемое функцией значение, и та же сигнатура. Указатель на функцию определяется следующим образом:

    тип_функции   (*имя_ухазателя)(спецификация_параметров);

    Например: int (*func1Ptr) (char); - определение указателя func1Ptr на функцию с параметром типа char, возвращающую значение типа int.

    Если приведенную синтаксическую конструкцию записать без первых круглых скобок, т.е. в виде int *fun (char); то компилятор воспримет ее как прототип некой функции с именем fun и параметром типа char, возвращающей значение указателя типа int *.

    Второй пример: char * (*func2Ptr) (char * ,int); - определение указателя func2Ptr на функцию с параметрами типа указатель на char и типа int, возвращающую значение типа указатель на char.

    В определении указателя на функцию тип возвращаемого значения и сигнатура (типы, количество и последовательность параметров) должны совпадать с соответствующими типами и сигнатурами тех функций, адреса которых предполагается присваивать вводимому указателю при инициализации или с помощью оператора присваивания. В качестве простейшей иллюстрации сказанного приведем программу с указателем на функцию:

//RAZN1_1.СРР -  определение и использование указателей на функции.
#include <iostream.h> // Для ввода-вывода.
void f1(void)        // Определение f1.
  { cout << "\nВыполияется f1()"; }
void f2(void)        // Определение f2.
  { cout << "\nВыполняется f2()"; }
void main()
{ void (*ptr)(void);  // ptr - указатель на функцию.
ptr = f2;	// Присваивается адрес f2().
(*ptr)();	// Вызов f2() по ее адресу.
ptr = f1;	// Присваивается адрес f1().
(*ptr)();	// Вызов f1() по ее адресу.
ptr();	// Вызов эквивалентен (*ptr)();
}
Текст этой программы можно взять здесь.

    Результат выполнения программы:

    Выполняется f2() 
    Выполняется f1() 
    Выполняется f1()

    В программе описан указатель ptr на функцию, и ему последовательно присваиваются адреса функций f2 и f1. Заслуживает внимания форма вызова функции с помощью указателя на функцию:

    (*имя_указателя)(список_фактических_параметров);

    Здесь значением имени_указателя служит адрес функции, а с помощью операции разыменования * обеспечивается обращение по адресу к этой функции. Однако будет ошибкой записать вызов функции без скобок в виде *ptr();. Дело в том, что операция () имеет более высокий приоритет, нежели операция обращения по адресу *. Следовательно, в соответствии с синтаксисом будет вначале сделана попытка обратиться к функции ptr(). И уже к результату будет отнесена операция разыменования, что будет воспринято как синтаксическая ошибка.

    На следующем шаге мы продолжим рассматривать указатели на функции.




Содержание Следующий шаг