Как работает определение дружественной функции внутри класса?

#include <iostream>

class Object { 
public:
  // friend std::ostream& operator<<(std::ostream& os, const Object & r) {/**/ return os;}
  friend void fOUT (void) { }
};

//! void fOUT (void) { } //redefinition of 'void fOUT()'

int main (void) {
  //! fOUT(); //  'fOUT' was not declared in this scope
  //! Object::fOUT(); // 'fOUT' is not a member of 'Object'

}


Как я понимаю, эта техника позволяет писать перегрузку оператора внутри класса, как будто это член класса, а не глобальная бинарная дружественная функция. Это наглядно.
Но почему такая же логика не работает с обычной функцией?
  • Вопрос задан
  • 139 просмотров
Решения вопроса 1
@MarkusD Куратор тега C++
все время мелю чепуху :)
Перегрузка большинства операторов может быть произведена любым из двух способов: внешней функцией или методом класса. Лишь некоторые операторы невозможно перегрузить в виде внешней функции, их перегрузка осуществляется только в виде метода класса.
Иными словами, все операторы можно перегрузить в виде метода и только некоторые - в виде внешней функции.
Разница между перегрузкой в виде внешней функции и перегрузкой в виде метода состоит в том, что метод является частью интерфейса класса и имеет доступ к его непубличным объявлениям, а внешняя функция частью интерфейса не является и доступ имеет только к публичным объявлениям класса.

Дружественность к перегрузке операторов не имеет никакого отношения. Перегрузка оператора в виде внешней функции и добавление дружественности для этой перегрузки выглядит как признак незнания стандарта в плане перегрузки операторов. Потому что в этом случае перегрузку нужно проводить в виде метода.
Исключением являться может только определение перегрузки оператора по месту объявления дружественности. Я уже объяснял почему это может быть удобно.
Такая перегрузка становится только 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 смог найти ее при обращении. Поэтому такая конструкция является бесполезной.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы