Функции и классы Friend предоставляют прямой доступ к закрытым и защищенным членам класса, чтобы избежать нарушения инкапсуляции в общем случае. Большая часть использования с ostream: мы хотели бы иметь возможность набирать:
Point p;
cout << p;
Однако для этого может потребоваться доступ к закрытым данным Point, поэтому мы определяем перегруженный оператор
friend ostream& operator<<(ostream& output, const Point& p);
Однако существуют очевидные последствия инкапсуляции. Во-первых, теперь у класса или функции друга есть полный доступ ко ВСЕМ членам класса, даже к тем, которые не относятся к его потребностям. Во-вторых, реализации класса и друга теперь запутаны до такой степени, что внутреннее изменение в классе может сломать друга.
Если вы рассматриваете друга как расширение класса, то, по логике говоря, это не проблема. Но, в таком случае, зачем было сначала выделять друга.
Чтобы достичь того же, чего преследуют «друзья», но не нарушая инкапсуляцию, можно сделать следующее:
class A
{
public:
void need_your_data(B & myBuddy)
{
myBuddy.take_this_name(name_);
}
private:
string name_;
};
class B
{
public:
void print_buddy_name(A & myBuddy)
{
myBuddy.need_your_data(*this);
}
void take_this_name(const string & name)
{
cout << name;
}
};
Инкапсуляция не нарушена, класс B не имеет доступа к внутренней реализации в A, но результат такой же, как если бы мы объявили B другом A.
Компилятор оптимизирует вызовы функций, поэтому это приведет к тем же инструкциям, что и для прямого доступа.
Я думаю, что с помощью «друга» просто ярлык с спорной выгодой, но определенной стоимостью.