Выбрать главу

SmallInt operator+ ( const myFloat & );

// ...

};

SmallInt operator+ ( const SmallInt &, double );

}

int main() {

// тип si - class SmallInt:

// Этот класс объявлен в пространстве имен NS

NS::SmallInt si(15);

int res = si + 5.66; // какой operator+()?

return 0;

}

В эти пять множеств входят семь операторных функций-кандидатов на роль operator+() в main(): первое множество пусто. В глобальной области видимости, а именно в ней употреблен operator+() в функции main(), нет объявлений перегруженного оператора operator+(); второе множество содержит операторы, объявленные в пространстве имен NS, где определен класс SmallInt. В этом пространстве имеется один оператор:

NS::SmallInt NS::operator+( const SmallInt &, double );

третье множество содержит операторы, объявленные друзьями класса SmallInt. Сюда входит

NS::SmallInt NS::operator+( const SmallInt &, int );

четвертое множество содержит операторы, объявленные членами SmallInt. Такой тоже есть:

NS::SmallInt NS::SmallInt::operator+( const myFloat & );

пятое множество содержит встроенные бинарные операторы:

int operator+( int, int );

double operator+( double, double );

T* operator+( T*, I );

T* operator+( I, T* );

Да, формирование множества кандидатов для разрешения оператора, использованного с применением операторного синтаксиса, утомительно. Но после того как оно построено, устоявшие функции и наилучшая из них находятся, как и прежде, путем анализа преобразований, применимых к операндам отобранных кандидатов.

15.12.2. Устоявшие функции

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

NS::SmallInt si(15);

si + 5.66;

Левый операнд имеет тип SmallInt, а правый – double.

Первый кандидат является устоявшей функцией для данного использования operator+():

NS::SmallInt NS::operator+( const SmallInt &, double );

Левый операнд типа SmallInt в качестве инициализатора точно соответствует формальному параметру-ссылке этого перегруженного оператора. Правый, имеющий тип double, также точно соответствует второму формальному параметру.

Следующая функция-кандидат также устоит:

NS::SmallInt NS::operator+( const SmallInt &, int );

Левый операнд si типа SmallInt в качестве инициализатора точно соответствует формальному параметру-ссылке перегруженного оператора. Правый имеет тип int и может быть приведен к типу второго формального параметра с помощью стандартного преобразования.

Устоит и третья функция-кандидат:

NS::SmallInt NS::SmallInt::operator+( const myFloat & );

Левый операнд si имеет тип SmallInt, т.е. тип того класса, членом которого является перегруженный оператор. Правый имеет тип int и приводится к типу класса myFloat с помощью определенного пользователем преобразования в виде конструктора myFloat(double).

Четвертой и пятой устоявшими функциями являются встроенные операторы:

int operator+( int, int );

double operator+( double, double );

Класс SmallInt содержит конвертер, который может привести значение типа SmallInt к типу int. Этот конвертер используется вместе с первым встроенным оператором для преобразования левого операнда в тип int. Второй операнд типа double трансформируется в тип int с помощью стандартного преобразования. Что касается второго встроенного оператора, то конвертер приводит левый операнд от типа SmallInt к типу int, после чего результат стандартно преобразуется в double. Второй же операнд типа double точно соответствует второму параметру.

Лучшей из этих пяти устоявших функций является первая, operator+(), объявленная в пространстве имен NS:

NS::SmallInt NS::operator+( const SmallInt &, double );

Оба ее операнда точно соответствуют параметрам.

15.12.3. Неоднозначность

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

class String {

// ...

public:

String( const char * = 0 );

bool operator== ( const String & ) const;

// нет оператора operator== ( const char * )

};

и такое использование оператора operator==: