В каких случаях следует объявлять функцию-член другом? - PullRequest
5 голосов
/ 21 февраля 2009

В каких случаях мы объявляем функцию-член как «функцию друга»? .. Какую конкретную цель выполняет «функция друга», которая противоречит одному из основных понятий «инкапсуляция» ООП?

Ответы [ 6 ]

2 голосов
/ 21 февраля 2009

Функции и классы друзей не нарушают инкапсуляцию, когда вы пытаетесь создать абстракцию или интерфейс, который должен физически охватывать несколько классов или функций C ++! Вот почему друг был изобретен.

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

Я также вспоминаю, как делал это при программировании на CORBA в C ++. CORBA заставил меня иметь отдельные классы для реализации слуг CORBA. Но для определенной части нашего программного обеспечения мне нужно было объединить их в один интерфейс. Дружба позволила этим двум классам работать вместе, чтобы обеспечить бесперебойную работу одной части нашего программного обеспечения.

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

2 голосов
/ 21 февраля 2009

Вы будете использовать функцию друга по тем же причинам, что и класс друга, но на основе функции-члена (а не всего класса). Некоторые хорошие объяснения есть в этой теме .

Хотя дружественные функции и классы нарушают инкапсуляцию, они могут быть полезны в некоторых сценариях. Например, вы можете разрешить тестовому устройству получать доступ к внутренним объектам класса, чтобы вы могли выполнять тестирование в «белой коробке». Вместо того, чтобы открывать весь класс для тестового жгута, вы можете открыть определенную функцию, которая обращается к внутренним компонентам, необходимым для тестового жгута. Хотя это все еще нарушает инкапсуляцию, это менее рискованно, чем открытие всего класса.

Также см. в этой статье для получения дополнительной информации о классах и функциях друзей.

1 голос
/ 21 февраля 2009

См. C ++ FAQ Lite:

Иногда друзья синтаксически лучше (например, в классе Fred функции друзей позволяют параметру Fred быть вторым, в то время как члены требуют, чтобы он был первым). Другим хорошим использованием дружественных функций являются двоичные арифметические операторы инфикса. Например, aComplex + aComplex должен быть определен как друг, а не член, если вы также хотите разрешить aFloat + aComplex (функции-члены не допускают продвижение левого аргумента, поскольку это приведет к изменению класса объекта получатель вызова функции-члена).

0 голосов
/ 07 декабря 2009

Вот простой, конкретный пример того, как я использую функцию друга:

У меня есть игра, в которой каждый спрайтовый объект хранит свою информацию, такую ​​как позиция X, Y, как личный член Однако я хочу отделить игровые объекты от рендеринга: игровой объект не нуждается в точных деталях того, как он отображается. Игровой объект хранит только игровое состояние, и это игровое состояние может быть воспроизведено различными способами.

Таким образом, класс игрового объекта имеет функцию друга: render (). Функция render () реализована вне класса игрового объекта, но она может обращаться к мембранам положения X, Y по мере необходимости для рендеринга игрового объекта.

0 голосов
/ 21 мая 2009

Один момент, который я считаю уместным: классы-члены имеют доступ к закрытым частям содержащего их класса. Иногда это может быть лучшей альтернативой «другу».

class A
{
private:
  int b;
public:
  class MemberNotFriend {
  public:
    static void test() {
      A a;
      a.b = 0;
    }
  };


};


void test()
{
  A::MemberNotFriend::test();
}
0 голосов
/ 21 февраля 2009

Иногда уровень общественной / частной / защищенной защиты не вполне достаточен для реальных ситуаций. Таким образом, мы даем небольшое предложение get-out, которое помогает без необходимости делать методы общедоступными.

Лично я использую это так же, как Java использует уровень защиты «Пакет».
Если у меня есть класс в том же пакете, который требует доступа, я рассмотрю возможность использования друга. Если это класс в другом пакете, то я удивлюсь, зачем другому классу нужен доступ, и посмотрю на мой дизайн.

...