Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка Программирование C++ 2014n.docx
Скачиваний:
8
Добавлен:
01.07.2025
Размер:
887 Кб
Скачать
☆

11.2. Передача имен функций в качестве параметров

Функцию можно вызвать через указатель на нее. Для этого объявляется указатель соответствующего типа и ему с помощью операции взятия адреса присваивается адрес функции:

void f(int a){ /*…*/ } // определение функции

void (*pf)(int); // указатель на функцию

…

pf=&f; //указателю присваивается адрес функции

//(можно написать pf=f;)

pf(10); //функция f вызывается через указатель pf

//(можно написать (*pf)(10) )

Для того чтобы сделать программу легко читаемой, при описании указателей на функции используют переименование типов (typedef). Можно объявлять массивы указателей на функции (это может быть полезно, например, при реализации меню):

//Описание типа PF как указателя

//на функцию с одним параметром типа int:

typedef void (*pf)(int);

//Описание и инициализация массива указателей:

pf menu[]= {&new, &open, save};

// Вызов функции open

menu[1](10);

Здесь new, open, и save - имена функций которые должны быть объявлены ранее. Указатели на функции передаются в программу таким же образом как и параметры других типов:

#include<iostream.h>

typedef void (*PF)(int);

void f1(PF pf)

{ //функция f1 получает в качестве параметра указатель типа pf

pf(5) //вызов функции, переданной через указатель

}

void f(int i ) {cout <<i}

int main()

{

f1(f);

return 0;

}

Тип указателя и тип функции, которая вызывается посредством этого указателя, должны совпадать в точности.

11.3. Перегрузка функций

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

Использование нескольких функций с одним и тем же именем, но с различными типами параметров, называется перегрузкой функций.

Компилятор определяет, какую именно функцию требуется вызвать, по типу фактических параметров. Этот процесс называется разрешением перегрузки (перевод английского слова resolution в смысле «уточнение»). Тип возвращаемого функцией значения в разрешении не участвует. Механизм разрешения основан на достаточно сложном наборе правил, смысл которых сводится к тому, чтобы использовать функцию с наиболее подходящими аргументами и выдать сообщение, если такой не найдется. Допустим, имеется четыре варианта функции, определяющей наибольшее значение:

// Возвращает наибольшее из двух целых:

int max(int, int);

// Возвращает подстроку наибольшей длины:

char* max(char*, char*);

// Возвращает наибольшее из первого параметра и длины второго:

int max (int, char*);

// Возвращает наибольшее из второго параметра и длины первого:

int max (char*, int);

void f(int a, int b, char* c, char* d)

{

cout << max (a,b) << max (c,d) << max (a,c) << max (c,b);

}

При вызове функции max компилятор выбирает соответствующий типу фактических параметров вариант функции (в приведенном примере будут последовательно вызваны все четыре варианта функции).

Если точного соответствия не найдено, выполняются продвижения порядковых типов в соответствии с общими правилами (см. [1] с. 38 и приложение 3), например, bool и char в int, float и double и т.п. Далее выполняются стандартные преобразования типов, например, int в double или указателей в void*. Следующим шагом является выполнение преобразований типа, заданных пользователем (об этих преобразованиях рассказывается во второй части [1], с. 195), а также поиск соответствий за счет переменного числа аргументов функций. Если соответствие на одном и том же этапе может быть получено более чем одним способом, вызов считается неоднозначным и выдается сообщение об ошибке.

Неоднозначность может появиться при:

  • преобразовании типа;

  • использовании параметров-ссылок;

  • использовании аргументов по умолчанию.

Ниже приведены правила описания перегруженных функций.

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

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

  • Функции не могут быть перегружены, если описание их параметров отличается только модификатором const или использованием ссылки (например, int и const int или int&).