Перегрузка операторов и дружба - это ортогональные понятия.Вам нужно объявлять функцию (любую функцию) friend
всякий раз, когда ей нужен доступ к закрытому члену типа, поэтому, если вы перегружаете оператор как функцию, которая не является членом, и этой реализации необходим доступ к закрытым членам, тогдаон должен быть другом.
Обратите внимание, что в общем случае лучше не объявлять friend
s, так как это самое высокое отношение связи в языке, поэтому, когда это возможно, вы должны реализовывать даже свободные перегрузки функций операторов вусловия открытого интерфейса вашего типа (что позволяет вам изменять реализацию типа без необходимости переписывать операторы).В некоторых случаях рекомендуется использовать operatorX
как свободную функцию в терминах operatorX=
, реализованную как открытую функцию-член (подробнее о перегрузке операторов здесь )
Существуетконкретный угловой случай с шаблонами классов, где вы можете объявить оператор свободной функции в качестве друга шаблона, чтобы иметь возможность определить его внутри класса шаблона, даже если ему не нужен доступ к закрытым членам:
template <typename T>
class X {
int m_data;
public:
int get_value() const { return m_data; }
friend std::ostream& operator<<( std::ostream& o, X const & x ) {
return o << x.get_value();
}
};
Это имеет то преимущество, что вы определяете одну функцию без шаблонов как друга простым и понятным способом.Чтобы переместить определение за пределы шаблона класса, вы должны будете сделать его шаблоном , а синтаксис становится более громоздким.