Здавалка
Главная | Обратная связь

Иллюстрируем на практике.



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

#include <iostream>using namespace std;void f1(void) // Определение f1.{ cout << "Load f1()\n"; }void f2(void) // Определение f2.{ cout << "Load f2()\n";}void main(){ void (*ptr)(void); // ptr - указатель на функцию. ptr = f2; // Присваивается адрес f2(). (*ptr)(); // Вызов f2() по ее адресу. ptr = f1; // Присваивается адрес f1(). (*ptr)(); // Вызов f1() по ее адресу. ptr(); // Вызов эквивалентен (*ptr)();}Результат выполнения программы: Load f2() Load f1() Load f1() Press any key to continue

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

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

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

char f1(char) {...} // Определение функции.char f2(int) {...} // Определение функции.void f3(float) {...} // Определение функции.int* f4(char *){...} // Определение функции.char (*pt1)(int); // Указатель на функцию.char (*pt2)(int); // Указатель на функцию.void (*ptr3)(float) = f3; // Инициализированный указатель.void main(){ pt1 = f1; // Ошибка - несоответствие сигнатур. pt2 = f3; // Ошибка - несоответствие типов (значений и сигнатур). pt1 = f4; // Ошибка - несоответствие типов. pt1 = f2; // Правильно. pt2 = pt1; // Правильно. char с = (*pt1)(44); // Правильно. с = (*pt2)('\t'); // Правильно.}

Следующая программа отражает гибкость механизма вызовов функций с помощью указателей.

#include <iostream>using namespace std;// Функции одного типа с одинаковыми сигнатурами:int add(int n, int m) { return n + m; }int division(int n, int m) { return n/m; }int mult(int n, int m) { return n * m; }int subt(int n, int m) { return n - m; }void main(){ int (*par)(int, int); // Указатель на функцию. int a = 6, b = 2; char c = '+'; while (c != ' ') { cout << "\n Arguments: a = " << a <<", b = " << b; cout << ". Result for c = \'" << c << "\':"; switch (c) { case '+': par = add; c = '/'; break; case '-': par = subt; c = ' '; break; case '*': par = mult; c = '-'; break; case '/': par = division; c = '*'; break; } cout << (a = (*par)(a,b))<<"\n"; //Вызов по адресу. }}Результаты выполнения программы: Arguments: a = 6, b = 2. Result for c = '+':8 Arguments: a = 8, b = 2. Result for c = '/':4 Arguments: a = 4, b = 2. Result for c = '*':8 Arguments: a = 8, b = 2. Result for c = '-':6 Press any key to continue

Цикл продолжается, пока значением переменной c не станет пробел. В каждой итерации указатель par получает адрес одной из функций, и изменяется значение c. По результатам программы легко проследить порядок выполнения ее операторов.







©2015 arhivinfo.ru Все права принадлежат авторам размещенных материалов.