- •1 Использование описания typedef
- •2 Преобразование типов
- •3 Указатели на функции
- •4 Пример использования указателей на функции
- •5 Области видимости и время жизни объектов
- •6 Пример использования статической локальной переменной
- •Примечание
- •7 Пространства имен
- •9 Подходы к разработке структуры программы
- •8 Заголовочные файлы
- •11 Задания на самостоятельную работу Задание 1
- •Задание 2
3 Указатели на функции
Возможны только две операции с функциями: вызов и взятие адреса. Указатель, полученный с помощью последней операции, можно впоследствии использовать для вызова функции. Сама функция не является переменной, в то же время указатель на нее является такой переменной, и с ним можно работать как с переменной: присваивать, передавать в качестве параметра функции, возвращать как результат из функции и т.д.
В С++ функции имеют тип. Имя функции не является частью типа этой функции. Тип функции определяется типом возвращаемого ей значения и списком ее формальных параметров. Указатель на функцию должен тоже описываться с тем же списком параметров и типом возвращаемого значения:
int (*pf)(int);
Скобки вокруг *pf обязательны. В противном случае мы бы имели объявление функции с целым параметром, возвращающей указатель на int. Теперь переменной pf можно присвоить адрес реальной функции соответствующего типа.
int f(int k)
{
return k;
}
int main()
{
int (*pf)(int);
pf = f;
...
}
Имя функции без следующих за ним скобок интерпретируется как указатель на функцию. Указатель на функцию применяется для вызова функции, которую он адресует. Включать оператор разыменования при этом необязательно. И прямой вызов функции по имени, и косвенный вызов по указателю записываются одинаково.
cout << f(3); // Вызов функции f
cout << pf(3); // То же самое
Часто для удобства определяют синоним типа указателя на функцию через typedef:
typedef int (*FuncType)(int);
FuncType pf;
Указатели на функцию чаще всего используются в качестве формальных параметров других функций.
Указатели могут адресовать варианты перегруженной функции. При этом транслятор подбирает вариант, находя точное сопоставление списка формальных параметров и типа возвращаемого значения. Если такого точного сопоставления нет, то будет сообщение об ошибке.
4 Пример использования указателей на функции
Допустим, необходимо реализовать программу, содержащую функцию определения корня уравнения на заданном интервале методом деления отрезка пополам. Параметры функции - интервал, указатель на функцию, задающую левую часть уравнения, и точность (по умолчанию точность равна 0.001).
Алгоритм нахождения корня методом деления отрезка пополам (дихотомии) заключается в следующем. Определяется середина интервала как среднее арифметическое значений начала и конца интервала. Сравнивается знак функции в начале и в середине интервала. Если знаки одинаковы, то начало интервала переносится в середину, в противном случае в середину переносится конец интервала. Таким образом, интервал сузился вдвое. Далее снова определяется его середина и процедура повторяется до тех пор, пока интервал не станет короче заданного значения (точности).
Функция нахождения корня методом деления отрезка пополам должна иметь возможность вызывать функцию, задающую левую часть уравнения, для различных значений аргумента. Указатель на такую функцию передается в качестве параметра. Вначале опишем тип указателя на функцию получающую аргумент типа double, и возвращающую результат того же типа:
typedef double (*FuncType)(double);
Определим функцию нахождения корня методом деления отрезка пополам с параметрами, задающими начало и конец интервала, указателем на функцию и необязательным параметром "точность" (eps):
double getRoot(double a, double b, FuncType f, double eps = 0.001)
{
В теле функции определяется средняя точка и реализуется цикл в соответствии с описанным выше алгоритмом:
double c;
do
{
c = (a + b) / 2;
if (f(a) * f(c) > 0)
a = c;
else
b = c;
}
while (b - a > eps);
return (a + b) / 2;
}
Для тестирования функции нахождения корня можно предложить небольшую функцию:
double g(double x)
{
return x * x - 2;
}
В функции вызывается функция нахождения корня с различными значениями точности:
int main(int argc, char* argv[])
{
cout << getRoot(0, 2, g) << endl; // Точность по умолчанию
cout << getRoot(0, 2, g, 0.000001) << endl;
return 0;
}
