HTML [44] |
Visual C++ и MFC [21] |
c++ [78] |
php [19] |
Javascript [15] |
C# [51] |
загрузки [0] |
XNA
[10]
создание игр с помощью xna
|
Главная » Статьи » c++ |
Прежде чем вводить указатель на функцию, напомним, что каждая функция характеризуется типом возвращаемого значения, именем, количеством, порядком следования и типами параметров. При использовании имени функции без последующих скобок и параметров имя функции выступает в качестве указателя на эту функцию, и его значением служит адрес размещения функции в памяти. Это значение адреса может быть присвоено другому указателю, и затем уже этот новый указатель можно применять для вызова функции. Однако в определении нового указателя должен быть тот же тип, что и возвращаемое функцией значение, то же количество, порядок следования и типы параметров. Указатель на функцию определяется следующим образом: тип функции (*имя_указателя)(спецификация_параметров); Например: int(*func1ptr) (char); — определение указателя func1ptr на функцию с параметром типа char, возвращающую значение типа int. Если приведенную синтаксическую конструкцию записать без первых круглых скобок, то есть в виде int *fun(char); то компилятор воспримет ее как прототип некой функции с именем fun и параметром типа char, возвращающей значение указателя типа int *. Второй пример: char * (*func2Ptr) (char *, int); - определение указателя func2Ptr на функцию с параметрами типа указатель на char и типа int, возвращающую значение типа указатель на char. В определении указателя на функцию тип возвращаемого значения и сигнатура (типы, количество и последовательность параметров) должны совпадать с соответствующими типами и сигнатурами тех функций, адреса которых предполагается присваивать вводимому указателю при инициализации или с помощью оператора присваивания. В качестве простейшей иллюстрации — небольшой пример: Пример №1/*Пример определения и использования указателей на функции */ #include<iostream.h> // описание функции f1 void f1(void) { cout << "\n Выполняется f1()"; } // описание функции f2 void f2(void) { cout << "\n Выполняется f2()"; } void main() { // объявление указателя на функцию, void (*ptr)(void); // ptr - указатель на функцию ptr = f2; // ptr инициализируется адресом f2() (*ptr)(); // вызов f2() по ее адресу ptr = f1; // присваивается адрес f1() (*ptr)(); // вызов f1() по ее адресу ptr(); // вызов эквивалентен (*ptr)(); } Результат выполнения программы:Выполняется f2() Выполняется f1() Выполняется f1() В программе описан указатель ptr на функцию, и ему последовательно присваиваются адреса функции f2 и fl. Обратите внимание на форму вызова функции с помощью указателя на функцию: (*имя_укаэателя)(список_фактических_параметров); Значением имени_указателя служит адрес функции, а с помощью операции разыменования * обеспечивается обращение по адресу к этой функции. Однако будет ошибкой записать вызов функции без скобок в виде *ptr(); Дело в том, что операция () имеет более высокий приоритет, нежели операция обращения по адресу *. Следовательно, в соответствии с синтаксисом будет вначале сделана попытка обратиться к функции ptr(). И уже к результату будет отнесена операция разыменования, что будет воспринято как синтаксическая ошибка. При определении указатель на функцию может быть инициализирован. В качестве инициализирующего значения должен использоваться адрес функции, тип и сигнатура(типы, количество и последовательность параметров) которой соответствуют определяемому указателю. При присваивании указателей на функции также необходимо соблюдать соответствие типов возвращаемых значении функции и сигнатур для указателей правой и левой частей оператора присваивания. То же справедливо и при последующем вызове функций с помощью указателей, т.е. типы и количество фактических параметров, используемых при обращении к функции по адресу, должны соответствовать формальным параметрам вызываемой функции. Следующая программа иллюстрирует гибкость механизма вызовов функций с помощью указателей. Пример №2/*Вызов функций по адресам через указатель */ #include<iostream.h> // описания функций // функции одного типа с одинаковыми сигнатурами int add (int n, int m) { return n + m;} int div (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; /* задаются начальные значения для переменных a и b */ char c = '+'; while(c != ' ') { cout << "\nАргументы: а = " << a << ", b = " << b; cout << "\n Результат для с = \'" << c << "\'" << " равен "; switch(c) { case '+': par = add; // par получает адрес функции add c = '%'; break; case '-': par = subt; // par получает адрес функции subt c = ' '; break; case '*': par = mult; // par получает адрес функции mult c = '-'; break; case '%': par = div; // par получает адрес функции div c = '*'; break; } cout << (*par)(a,b); /* вызов функции по адресу, результат, возвращаемый функцией, выводится на экран */ } cout << endl; } Результат выполнения программыАргументы: a = 6, b = 2. Результат для с = '+' равен 8 Аргументы: a = 6, b = 2. Результат для с = '%' равен 0 Аргументы: a = 6, b = 2. Результат для с = '*' равен 12 Аргументы: a = 6, b = 2. Результат для с = '-' равен 4 Цикл продолжается, пока значением переменной с не станет пробел. В каждой итерации указатель par получает адрес одной из функций, и изменяется значение с. По результатам программы легко проследить порядок выполнения ее операторов. Указатели на функции могут быть объединены в массивы. Например, float (*ptrArray) (char) [4] ; - описание массива с именем ptrArray из четырех указателей на функции, каждая из которых имеет параметр типа char и возвращает значение типа float. Чтобы обратиться, например, к третьей из этих функций, потребуется такой оператор: float a = (*ptrArray[2]) ('f'); Как обычно, индексация массива начинается с 0, и поэтому третий элемент массива имеет индекс 2. Массивы указателей на функции удобно использовать при разработке всевозможных меню, точнее программ, управление которыми выполняется с помощью меню. Для этого действия, предлагаемые на выбор будущему пользователю программы, оформляются в виде функций, адреса которых помещаются в массив указателей на функции. Пользователю предлагается выбрать из меню нужный ему пункт и по номеру пункта, как по индексу, из массива выбирается соответствующий адрес функции. Обращение функции к этому адресу обеспечивает выполнение требуемых действий. Самую общую схему реализации такого подхода иллюстрирует следующая программа. Пример №3/*пример с массивом указателей на функции */ #include<iostream.h> // объявление функций void func1(int); void func2(int); void func3(int); void main() { /* объявление массива, в котором хранятся указатели на функции func1, func2 и func3*/ void (*f[3])(int) = {func1, func2, func3}; int choice; cout << "Введите число между 1 и 3," " другое число - окончание: "; cin >> choice; while(choice >= 1 && choice < 4) { (*f[choice-1])(choice); // вызов функции f[choice] cout << "Введите число между 1 и 3," " другое число - окончание: "; cin >> choice; } cout << "Вы ввели " << choice << " для окончания\n"; } // описания функций void func1(int a) { cout << "\nВы ввели " << a << ", поэтому была вызвана func1\n"; } void func2(int b) { cout << "\nВы ввели " << b << ", поэтому была вызвана func2\n"; } void func3(int a) { cout << "\nВы ввели " << a << ", поэтому была вызвана func3\n"; } Результаты выполнения программыВведите число между 1 и 3, другое число - окончание: 1 Вы ввели 1, поэтому была вызвана func1 Введите число между 1 и 3, другое число - окончание: 2 Вы ввели 2, поэтому была вызвана func2 Введите число между 1 и 3, другое число - окончание: 3 Вы ввели 3, поэтому была вызвана func3 Введите число между 1 и 3, другое число - окончание: 10 Вы ввели 10 для окончания В программе определены три функции — func1, func2, func3 - каждая из которых принимает целый аргумент и ничего не возвращает. Указатели на эти три функции хранятся в массиве f, который объявлен следующим образом: void (*f[3])(int) = {func1, func2, func3};Массив получает в качестве начальных значений имена 3-х функций. Когда пользователь вводит значения 1, 2 или 3, это значение (минус 1) используется в качестве индекса в массиве указателей на функции. Вызов функции выполняется следующим образом: (*f[choice-1])(choice); В этом вызове (*f[choice-1]) определяет указатель, расположенный в элементе массива с индексом choice-1. Указатель разыменовывается, чтобы вызвать функцию, и choice передается функции как аргумент. Каждая функция печатает имя функции, чтобы показать, что вызов верен. | |
Просмотров: 10531 | Рейтинг: 4.9/7 |
Всего комментариев: 0 | |