Перегрузка большинства
операторов может быть произведена любым из двух способов: внешней функцией или методом класса. Лишь некоторые операторы невозможно перегрузить в виде внешней функции, их перегрузка осуществляется только в виде метода класса.
Иными словами, все операторы можно перегрузить в виде метода и только некоторые - в виде внешней функции.
Разница между перегрузкой в виде внешней функции и перегрузкой в виде метода состоит в том, что метод является частью интерфейса класса и имеет доступ к его непубличным объявлениям, а внешняя функция частью интерфейса не является и доступ имеет только к публичным объявлениям класса.
Дружественность к перегрузке операторов не имеет никакого отношения. Перегрузка оператора в виде внешней функции и добавление дружественности для этой перегрузки выглядит как признак незнания стандарта в плане перегрузки операторов. Потому что в этом случае перегрузку нужно проводить в виде метода.
Исключением являться может только определение перегрузки оператора по месту объявления дружественности. Я уже
объяснял почему это может быть удобно.
Такая перегрузка становится только ADL-доступной и не может быть вызвана через полную квалификацию имени.
Как я понимаю, эта техника позволяет писать перегрузку оператора внутри класса, как будто это член класса, а не глобальная бинарная дружественная функция.
Это не так. У тебя неверное понимание. Наверное ты уже подзабыл мое прошлое
объяснение по этому вопросу. Я рекомендую повторно обратиться к тому вопросу и ответу.
friend std::ostream& operator<<(std::ostream& os, const Object & r) {/**/ return os;}
Тут
operator <<
все так же остается глобальной функцией, определенной в том же пространстве имен, где определен и тип
Object
, но не в пространстве имен типа
Object
. Но, будучи определенным по месту объявления дружественности, оператор стал только ADL-доступным. Обращение к этому оператору может быть найдено только тогда, когда в конструкции
std::cout << obj;
этот
obj
имеет тип
Object
.
Но почему такая же логика не работает с обычной функцией?
Минимально, потому что операторы никак нельзя сравнивать ни с глобальными функциями, ни с методами. У операторов своя отдельная методика вызова, отличная от функций.
friend void fOUT (void) { }
, опять же, является определением по месту объявления дружественности и доступна только через ADL. Но у нее нет аргументов чтобы ADL смог найти ее при обращении. Поэтому такая конструкция является бесполезной.