Я думаю, что часто использование функции друга - это вопрос читабельности. Например, следующий перегруженный оператор выглядит симметрично, и это может быть полезно для читателя кода.
friend const X operator+(const X&, const X&);
inline const X operator+(const X& arg1, const X& arg2)
{
X r;
r.x = arg1.x + arg2.x;
return r;
}
Но главное в том, что они имеют доступ к приватным данным двух разных классов.