Введение в язык Си++

         

Перегрузка Имен Функций


Как правило, давать разным функциям разные имена - мысль хорошая, но когда некоторые функции выполняют одинаковую работу над объектами разных типов, может быть более удобно дать им одно и то же имя. Использование одного имени для различных действий над различными типами называется перегрузкой (overloading). Метод уже используется для основных операций C++: у сложения существует только одно имя, +, но его можно применять для сложения значений целых, плавающих и указательных типов. Эта идея легко расширяется на обработку операций, определенных пользователем, то есть, функций. Чтобы уберечь программиста от случайного повторного использования имени, имя может использоваться более чем для одной функции только если оно сперва описано как перегруженное. Например:

overload print; void print(int); void print(char*);

Что касается компилятора, единственное общее, что имеют функции с одинаковым именем, это имя. Предположительно, они в каком-то смысле похожи, но в этом язык ни стесняет программиста, ни помогает ему. Таким образом, перегруженные имена функций - это главным образом удобство записи. Это удобство значительно в случае функций с общепринятыми именами вроде sqrt, print и open. Когда имя семантически значимо, как это имеет место для операций вроде +, * и #5.2.4 и #6.3.1), это удобство становится существенным. Когда вызывается перегруженная f(), компилятор должен понять, к какой из функций с именем f следует обратиться. Это делается путем сравнения типов фактических параметров с типами формальных параметров всех функций с именем f. Поиск функции, которую надо вызвать, осуществляется за три отдельных шага:

[1] Искать функцию соответствующую точно, и использовать ее, если она найдена;

[2] Искать соответствующую функцию используя встроенные преобразования и использовать любую найденную функцию; и

[3] Искать соответствующую функцию используя преобразования, определенные пользователем (#6.3), и если множество преобразований единственно, использовать найденную функцию.

Например:


overload print(double), print(int);

void f(); { print(1); print(1.0); }

Правило точного соответствия гарантирует, что f напечатает 1 как целое и 1.0 как число с плавающей точкой. Ноль, char или short точно соответствуют параметру int. Аналогично, float точно соответствует double.

К параметрам функций с перегруженными именами стандартные C++ правила преобразования (#с.6.6) применяются не полностью. Преобразования, могущие уничтожить информацию, не выполняются. Остаются int в long, int в double, ноль в long, ноль в double и преобразования указателей: ноль в указатель, ноль в void*, и указатель на производный класс в указатель на базовый класс ().

Вот пример, в котором преобразование необходимо:

overload print(double), print(long);

void f(int a); { print(a); }

Здесь a может быть напечатано или как double, или как long. Неоднозначность разрешается явным преобразованием типа (или print(long(a)) или print(double(a))).

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

overload pow; int pow(int, int); double pow(double, double); // из complex pow(double, complex); // из complex pow(complex, int); complex pow(complex, double); complex pow(complex, complex);

Процесс поиска подходящей функции игнорирует unsigned и const.


Содержание раздела