Когда разумно использовать дружбу в ООП?

В настоящее время я изучаю учебник http://www.cplusplus.com, и я наткнулся на этот раздел здесь: http://www.cplusplus.com/doc/tutorial/inheritance.html , посвященный теме функций друзей. и друзья классы в C ++.

У меня вопрос, когда разумно использовать дружбу при создании программы?

Единственная подсказка, которую я получил, была в примере внутри статьи, который демонстрировал функцию друга, которая «дублировала» объект.

15.12.2008 00:44:34
5 ОТВЕТОВ

Для этого есть несколько хороших практических правил в C ++ FAQ Lite от Marshall Cline .

Все хорошо, но, в частности, смотрите: "Друзья нарушают инкапсуляцию?" примеры правильного способа их использования и когда лучше разделить классы и объявить их друзьями.

5
18.12.2012 13:01:20
Я использовал дружественные функции как часть интерфейса класса, предназначенного для вызова из кода Си. Мы объявляем дружественные функции в отдельном заголовке с искажением в стиле C и компилируем их исходный код как C ++.
John 12.12.2012 17:52:02

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

// binary operators where BigNum isn't the left-hand operand
BigNum operator+ (int, BigNum);
BigNum operator- (int, BigNum);

// stream operators
std::ostream &operator<< (std::ostream &os, const BigNum &num);
std::istream &operator>> (std::istream &is, BigNum &num);

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

4
15.12.2008 02:07:09
Я согласен с операторами << и >>. Но для вашего другого примера - не будет ли проще, если вы просто определите преобразование из int в BigNum?
Boyan 15.12.2008 09:41:35
Да, в случае BigNum, потому что int всегда также является BigNum. В других случаях может не иметь смысла создавать объект из LHS оператора.
Tom 15.12.2008 14:41:49
Автоматические преобразования обычно являются плохой идеей. Они могут странным образом взаимодействовать с определением типов и перегрузкой функций.
David Thornley 15.12.2008 20:43:05

Одно хорошее приложение для классов друзей - это шаблон дизайна Memento .

3
15.12.2008 03:15:19

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

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

0
15.12.2008 07:13:54
Ну, переопределение потоковых операторов не означает, что они станут друзьями. Если некоторая информация об объекте отображается с помощью оператора <<, мы можем предположить, что этот бит информации является общедоступным и, следовательно, существует средство получения доступа к нему.
Luc Touraille 15.12.2008 09:02:36
@Luc. Причина переопределения операторов потока в качестве друзей заключается в том, что класс потока (ostream или istream) находится в левой части оператора. Поэтому, если вы хотите переопределить оператор, используя функцию-член, он должен быть членом ostream или istream. Но вы не можете этого сделать, поэтому вы используете друга
Boyan 15.12.2008 09:40:02
Друзья не нарушают сокрытие данных. Друзья просто позволяют инкапсуляции класса включать свободные функции, а не только функции-члены.
Tom 16.12.2008 02:32:47
@Tom: «просто» допуская это, вы должны изменить что-то вне класса, когда вы измените внутреннее представление класса. И это нарушение сокрытия данных.
Boyan 16.12.2008 06:34:30
@ Боян - Нет. Друг является частью класса, даже если он не является синтаксически членом. Друг, вероятно, должен быть реализован в том же исходном файле, что и остальные классы, в любом случае.
Tom 16.12.2008 14:37:12

Я использовал только дружественные методы и свойства для использования внутри самого класса для клонирования самого себя или назначения другого объекта себе. Это было в значительной степени заменено, мы реорганизовали дизайн, чтобы внедрить шаблон Memento Design в наш дизайн.

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

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

0
15.12.2008 20:35:19