15.12.3. Неоднозначность
15.12.3. Неоднозначность
Наличие в одном и том же классе конвертеров, выполняющих неявные преобразования во встроенные типы, и перегруженных операторов может приводить к неоднозначности при выборе между ними. Например, есть следующее определение класса String с функцией сравнения:
class String {
// ...
public:
String( const char * = 0 );
bool operator== ( const String & ) const;
// нет оператора operator== ( const char * )
};
и такое использование оператора operator==:
String flower( "tulip" );
void foo( const char *pf ) {
// вызывается перегруженный оператор String::operator==()
if ( flower == pf )
cout pf " is a flower!en";
// ...
}
Тогда при сравнении
flower == pf
вызывается оператор равенства класса String:
String::operator==( const String & ) const;
Для трансформации правого операнда pf из типа const char* в тип String параметра operator==() применяется определенное пользователем преобразование, которое вызывает конструктор:
String( const char * )
Если добавить в определение класса String конвертер в тип const char*:
class String {
// ...
public:
String( const char * = 0 );
bool operator== ( const String & ) const;
operator const char*(); // новый конвертер
};
то показанное использование operator==() становится неоднозначным:
// проверка на равенство больше не компилируется!
if (flower == pf)
Из-за добавления конвертера operator const char*() встроенный оператор сравнения
bool operator==( const char *, const char * )
тоже считается устоявшей функцией. С его помощью левый операнд flower типа String может быть преобразован в тип const char *.
Теперь для использования operator==() в foo() есть две устоявших операторных функции. Первая из них
String::operator==( const String & ) const;
требует применения определенного пользователем преобразования правого операнда pf из типа const char* в тип String. Вторая
bool operator==( const char *, const char * )
требует применения пользовательского преобразования левого операнда flower из типа String в тип const char*.
Таким образом, первая устоявшая функция лучше для левого операнда, а вторая – для правого. Поскольку наилучшей функции не существует, то вызов помечается компилятором как неоднозначный.
При проектировании интерфейса класса, включающего объявление перегруженных операторов, конструкторов и конвертеров, следует быть весьма аккуратным. Определенные пользователем преобразования применяются компилятором неявно. Это может привести к тому, что встроенные операторы окажутся устоявшими при разрешении перегрузки для операторов с операндами типа класса.
Упражнение 15.17
Назовите пять множеств функций-кандидатов, рассматриваемых при разрешении перегрузки оператора с операндами типа класса.
Упражнение 15.18
Какой из операторов operator+() будет выбран в качестве наилучшего из устоявших для оператора сложения в main()? Перечислите все функции-кандидаты, все устоявшие функции и преобразования типов, которые надо применить к аргументам для каждой устоявшей функции.
namespace NS {
class complex {
complex( double );
// ...
};
class LongDouble {
friend LongDouble operator+( LongDouble &, int ) { /* ... */ }
public:
LongDouble( int );
operator double();
LongDouble operator+( const complex & );
// ...
};
LongDouble operator
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Поздняя неоднозначность
Поздняя неоднозначность Как решить проблему преждевременной точности? Откладывая точные определения на как можно более поздний срок. Профессиональные разработчики не формулируют требования до того, как будут готовы к разработке. Однако такой подход может привести к
Проблема третья – неоднозначность
Проблема третья – неоднозначность Графологи не могут сойтись на определенном наборе признаков почерка. Каждый графолог или каждая школа, так или иначе, формирует свой набор. Интерпретируют они признаки тоже отчасти по-разному. Разные мнения и направления существуют во