Почему возможно определять определения функций друга внутри определения класса?

Не предполагается ли явное определение функции друга вне класса?
Если да, то почему я могу объявить функцию друга внутри определения класса так же, как любая функция-член?
Что это?
Это только ОК с некоторыми операторами, такими как < operator или применимо ко всем операторам?
Если это применимо ко всем из них, есть ли недостаток для этого?
Следует ли его избегать? Если да, то почему?

class person 
{
public:
    bool operator<(int num)
    {
        return  x < num ? true : false ;
    }
    bool operator<(person& p)
    {
        return  x < p.x ? true : false ;
    }

    friend bool operator<(int num, person &p)
    {
        return  p.x < num ? true : false ;
    }

    void setX(int num)
    {
        x = num;
    }

private:
    int x;


};

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

Ответ 1

Не предполагается ли явное определение функции друга вне класса?

Функции друга могут быть определены внутри деклараций классов. Эти функции являются встроенными функциями и похожими на встроенные функции членов, они ведут себя так, как если бы они были определены сразу после того, как все члены класса были замечены, но до того, как область класса закрыта (конец объявления класса). Функции Friend, определенные внутри деклараций класса, не рассматриваются в области охватывающего класса; они находятся в области файлов. котировка

Это только ОК с некоторыми операторами, такими как <operator или применимо ко всем операторам?

Лучше стараться избегать функций друзей, поскольку они противоположны тому, что вы пытаетесь сделать, используя область частного класса и главным образом "спрячь" переменные. Если все ваши функции - это функции друзей, то в чем заключается использование личных вариаций?

Тем не менее, есть некоторые общие операторы, которые часто объявляются как функции друзей, это operator<< и operator>>

Ответ 2

Поскольку оператор, который должен знать детали правой части выражения, в котором используется, если он должен обращаться к личным данным того типа, который находится на этой стороне, он должен быть friend с этим классом.

Если вы пытаетесь сравнить int с Person, как в вашем примере, выбор состоит из двух:

  • или вы предоставляете неявное преобразование из Person в int, чтобы < мог использовать его без доступа к любому частному полю
  • или вы объявляете оператора в качестве friend Person чтобы он мог получить доступ к x в rhs сравнения

Ответ 3

Как сказал Джек, функции друзей требуются в местах, где необходим доступ к конфиденциальным данным. Есть и другая цель. Это связано с типами наследования. Только производный класс и его друзья могут преобразовать указатель на частную базу в производный тип. Поэтому иногда вы можете сделать некоторую функцию другом производного класса, чтобы позволить этому внутреннему телу функции.

Ответ 4

Ответ Alexandru Barbarosie верен. Это означает, что мы можем объявить функцию друга, которая не является функцией-членом, внутри класса. Это может быть удобно организовать код. Я думаю, что пример может помочь понять это, если это не ясно.

#include <iostream>

class A {
    public:
        A(int val) : val(val) {}
        // The following isn't a member function, it is a friend 
        // function declared inside the class and it has file scope
        friend void draw (A &a) {
            std::cout << "val: " << a.val << "\n";
        }
    private:
        int val;
};

int main() {
    A a(5);
    draw(a); // outputs "val: 5"
    //A::draw(a); // Error: 'draw' is not a member of 'A'
}