Как правило, вовсе несложно выяснить, допустим ли вызов, и если он допустим, то какая из версий функции будет использована компилятором. Функции в наборе перегруженных версий отличаются количеством или типом аргументов. В таких случаях определить используемую функцию просто. Подбор функции усложняется в случае, когда количество параметров одинаково и они допускают преобразование (см. раздел 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&)
, которая соответствовала бы этому вызову, скрыта и не рассматривается.