При перегрузке функций возможно появление ошибок такого типа, какие нам раньше не встречались. Можно создать ситуацию, в которой компилятор не сможет выбрать между двумя или более перегруженными функциями. Когда такое происходит, говорят, что ситуация неопределенна, двусмысленна (ambiguous). Неопределенные инструкции являются ошибками, и программа, содержащая неопределенности, не будет откомпилирована.
Основная причина, которая может вызывать неопределенность, связана с автоматическим преобразованием типов в C++. C++ автоматически пытается преобразовать аргументы, использованные при вызове функции, к типу аргументов интерфейса функции. В качестве примера рассмотрим следующий фрагмент:
int F(double d);
cout << F('с'); // ошибки не происходит из-за преобразования
Как указано в комментарии, данный код не является ошибочным, потому что С автоматически конвертирует символ с в его эквивалент типа double. В C++ только немногие из подобных преобразований запрещены. Хотя автоматическое преобразование типов является очень удобным, оно служит наиболее распространенной причиной неопределенности. Например, рассмотрим следующую программу:
Здесь функция F() перегружена, так что она может иметь в качестве аргументов переменные типа float или double. Первая строка в функции main() не вызывает неопределенности, поскольку число 10.1 автоматически преобразуется в C++ к типу double и вызывается функция F() с аргументом типа double. Однако когда функция F() вызывается с использованием числа 10, возникает неопределенность, поскольку компилятор не может определить, приводить это число к типу float или типу double. Это вызывает сообщение об ошибке, и программа не компилируется.
Как показывает предыдущий пример, неопределенность вызвана не перегрузкой функции F, а вызовом этой функции с неопределенным типом аргумента, т.е. особенностями ее вызова.
Ниже приведен другой пример неопределенности, вызванной автоматическим преобразованием типа в языке C++:
#include <iostream.h>
char F(unsigned char ch) { return ch-1; }
char F(char ch) { return ch+1; }
int main()
{
cout << F('c'); // вызов F(char)
cout << F(88) << " "; // неопределенность
return 0;
}
В C++ unsigned char и char не являются двусмысленными. Тем не менее, когда функция F() вызывается с числом 88, компилятор не знает, какую из функций вызывать. Иными словами, следует ли 88 преобразовывать к char или к unsigned char?
Другой способ возникновения неопределенности связан с использованием в перегруженных функциях аргументов по умолчанию. Чтобы увидеть, как это происходит, рассмотрим следующую программу:
#include <iostream.h>
int F(int i) { return i; }
int F(int i, int j = 1) { return i*j; }
int main()
{
cout << F(4, 5) << " "; // неопределенности нет
cout << F(10); // неопределенность
return 0;
}
Здесь при первом вызове функции F() указываются два аргумента, так что неопределенность не возникает и вызывается функция F(int i, int j). Однако при втором вызове функции F() возникает двусмысленность, поскольку компилятор не знает, вызывать ли функцию F() с одним аргументом, или же использовать функцию с двумя аргументами, у которой второй аргумент принимает значение по умолчанию.