Как правило, вовсе несложно выяснить, допустим ли вызов, и если он допустим, то какая из версий функции будет использована компилятором. Функции в наборе перегруженных версий отличаются количеством или типом аргументов. В таких случаях определить используемую функцию просто. Подбор функции усложняется в случае, когда количество параметров одинаково и они допускают преобразование (см. раздел 4.11) переданных аргументов. Распознавание вызовов компилятором при наличии преобразований рассматривается в разделе 6.6, а пока следует понять, что при любом вызове перегруженной функции возможен один из трех результатов.
• Компилятор находит одну функцию, которая является
• Компилятор не может найти ни одной функции, параметры которой соответствуют аргументам вызова. В этом случае компилятор сообщает об ошибке
• Компилятор находит несколько функций, которые в принципе подходят, но ни одна из них не соответствует полностью. В этом случае компилятор также сообщает об ошибке, об ошибке
Упражнение 6.39. Объясните результат второго объявления в каждом из следующих наборов. Укажите, какое из них (если есть) недопустимо.
(a) int calc(int, int);
int calc(const int, const int);
(b) int get();
double get();
(c) int *reset(int *);
double *reset(double *);
Новички в программировании на языке С++ зачастую не понимают взаимодействия между областью видимости и перегрузкой. Однако у перегрузки нет никаких специальных свойств относительно области видимости. Как обычно, если имя объявлено во внутренней области видимости, оно
string read();
void print(const string &);
void print(double); //
void fooBar(int ival) {
bool read = false; //
//
string s = read(); //
//
//
//
void print(int); //
//
print("Value: "); //
print(ival); //
print(3.14); //
}
Большинство читателей не удивит ошибка при вызове функции read(). Когда компилятор обрабатывает вызов функции read(), он находит локальное определение имени read. Это имя принадлежит переменной типа bool, а не функции. Следовательно, вызов некорректен.
Точно тот же процесс используется при распознавании вызова функции print(). Объявление print(int) в функции fooBar скрывает прежнее ее объявление. В результате будет доступна только одна функция print(), та, которая получает один параметр типа int.
Когда происходит вызов функции print(), компилятор ищет сначала объявление этого имени. Он находит локальное объявление функции print(), получающей один параметр типа int. Как только имя найдено, компилятор игнорирует такое же имя в любой внешней области видимости. Он полагает данное объявление единственно доступным для использования. Остается лишь удостовериться в допустимости использования этого имени.
Первый вызов передает функции print() строковый литерал, но единственное ее объявление, находящееся в области видимости, имеет параметр типа int. Строковый литерал не может быть преобразован в тип int, поэтому вызов ошибочен. Функция print(const string&), которая соответствовала бы этому вызову, скрыта и не рассматривается.