Задать вопрос
Qubc
@Qubc
Ненавижу полисемию.

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

#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'

}


Как я понимаю, эта техника позволяет писать перегрузку оператора внутри класса, как будто это член класса, а не глобальная бинарная дружественная функция. Это наглядно.
Но почему такая же логика не работает с обычной функцией?
  • Вопрос задан
  • 144 просмотра
Подписаться 3 Простой Комментировать
Решения вопроса 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 смог найти ее при обращении. Поэтому такая конструкция является бесполезной.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы