14.9.3. Подбор функций и перегруженные операторы
Перегруженные операторы — это перегруженные функции. При выявлении, который из встроенных или перегруженных операторов применяется для данного выражения, используется обычный подбор функции (см. раздел 6.4). Однако, когда в выражении используется функция оператора, набор функций-кандидатов шире, чем при вызове функций, использующих оператор вызова. Если объект а имеет тип класса, то выражение a sym b может быть следующим:
a.operator sym(b); // класс а содержит оператор sym как функцию-член
operator sym(a, b); // оператор sym - обычная функция
В отличие от обычных вызовов функции, нельзя использовать форму вызова для различения функции-члена или не члена класса.
Когда используется перегруженный оператор с операндом типа класса, функции-кандидаты включают обычные версии, не являющиеся членами класса этого оператора, а также его встроенные версии. Кроме того, если левый операнд имеет тип класса, определенные в нем перегруженные версии оператора (если они есть) также включаются в набор кандидатов.
Когда вызывается именованная функция, функции-члены и не члены класса с тем же именем не перегружают друг друга. Перегрузки нет потому, что синтаксис, используемый для вызова именованной функции, различает функции- члены и не члены класса. При вызове через объект класса (или ссылку, или указатель на такой объект) рассматриваются только функции-члены этого класса. При использовании в выражении перегруженного оператора нет никакого способа указать на использование функции-члена или не члена класса. Поэтому придется рассматривать версии и функции-члены, и не члены класса.
Набор функций-кандидатов для используемого в выражении оператора может содержать функции-члены и не члены класса.
Определим, например, оператор суммы для класса SmallInt:
class SmallInt {
friend
SmallInt operator*(const SmallInt&, const SmallInt&);
public:
SmallInt(int = 0); // преобразование из int
operator int() const { return val; } // преобразование в int
private:
std::size_t val;
};
Этот класс можно использовать для суммирования двух объектов класса SmallInt, но при попытке выполнения смешанных арифметических операций возникнет проблема неоднозначности:
SmallInt s1, s2;
SmallInt s3 = s1 + s2; // использование перегруженного оператора +
int i = s3 + 0; // ошибка: неоднозначность
Первый случай суммирования использует перегруженную версию оператора + для суммирования двух значений типа SmallInt. Второй случай неоднозначен, поскольку 0 можно преобразовать в тип SmallInt и использовать версию оператора + класса SmallInt либо преобразовать объект s3 в тип int и использовать встроенный оператор суммы для типа int.
Предоставление функции преобразования в арифметический тип и перегруженных операторов для того же типа может привести к неоднозначности между перегруженными и встроенными операторами.
Упражнения раздела 14.9.3
Упражнение 14.52. Какой из операторов operator+, если таковые вообще имеются, будет выбран для каждого из следующих выражений суммы? Перечислите функции-кандидаты, подходящие функции и преобразования типов для аргументов каждой подходящей функции:
struct LongDouble {
// оператор-член operator+ только для демонстрации;
// обычно он не является членом класса
LongDouble operator+(const SmallInt&); // другие члены как в p. 14.9.2
};
LongDouble operator+(LongDouble&, double);
SmallInt si;
LongDouble ld;
ld = si + ld;
ld = ld + si;
Упражнение 14.53. С учетом определения класса SmallInt определите, допустимо ли следующее выражение суммы. Если да, то какой оператор суммы используется? В противном случае, как можно изменить код, чтобы сделать его допустимым?
SmallInt s1;
double d = s1 + 3.14;
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК