Класс друзей


Из Википедии, свободной энциклопедии
Перейти к навигации Перейти к поиску

Класс друга в C++ может получить доступ к закрытым и защищенным членам класса , в котором он объявлен как друг. [1] Дружественный класс используется для части структуры данных, представленной классом, для обеспечения доступа к основному классу, представляющему эту структуру данных. Механизм дружественного класса позволяет расширить хранилище и доступ к частям, сохраняя при этом правильную инкапсуляцию с точки зрения пользователей структуры данных.

Подобно классу друга, функция друга — это функция , которой предоставляется доступ к закрытым и защищенным членам класса, в котором она объявлена ​​как дружественная.

Пример

В следующем примере демонстрируется использование дружественного класса для структуры данных графа, где граф представлен основным классом Graph, а вершины графа представлены классом Vertex.

#include <иопоток> #include <память> #include <строка> #include <неупорядоченный_набор>  график классов ;класс  Вершина {  общественность : явный Vertex ( std :: string name ) : ребра_ (), name_ ( std :: move ( name )) {}       auto begin () const { return edge_ . cначало (); }       auto end () const { return edge_ . цента (); }       const auto & name () const { return name_ ; }        частный : // Vertex дает права доступа к Graph. График класса друзей ;    std :: unordered_set < Vertex *> edge_ ;  std :: имя_строки_ ; _ }; график класса {  общественность : ~ График () {  в то время как ( ! вершины_ . пусто ()) {   авто вершина = вершины_ . начать ();    Удалить Вершину ( * вершина ); } } auto AddVertex ( const std :: string & name ) -> Vertex * {       auto vertex = std :: make_unique < Vertex > ( имя );    авто итер = вершины_ . вставить ( вершина . получить ());    обратная вершина . освободить ();  } пустота RemoveVertex ( вершина * вершина ) {    вершины_ . стереть ( вершину ); удалить вершину ;  } auto AddEdge ( вершина * из , вершина * в ) {      // Graph может получить доступ к приватным полям Vertex, потому что Vertex объявил Graph // другом. от -> края_ . вставить ( в );   } auto begin () const { return vertices_ . cначало (); }       auto end () const { return vertices_ . цента (); }       частный : std :: unordered_set < Vertex *> vertices_ ; };

Инкапсуляция

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

Важно отметить, что класс не может предоставить себе доступ к закрытой части другого класса; это нарушит инкапсуляцию. Скорее, класс предоставляет доступ к своим собственным закрытым частям другому классу, объявляя этот класс другом. В примере с графом Graph не может объявить себя дружественной Vertex. Скорее, Vertex объявляет Graph другом и, таким образом, предоставляет Graph доступ к своим закрытым полям.

Тот факт, что класс сам выбирает себе друзей, означает, что дружба в общем случае не является симметричной. В примере с графом Vertex не может получить доступ к закрытым полям Graph, хотя Graph может получить доступ к закрытым полям Vertex.

Альтернативы

Аналогичная, но не эквивалентная языковая функция предоставляется внутренним ключевым словом C#, которое позволяет классам внутри одной сборки получать доступ к закрытым частям других классов. Это соответствует пометке каждого класса как друга другого в той же сборке; классы друзей более детализированы.

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

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

Характеристики

  • Дружба не симметрична  : если класс Aявляется другом класса B, класс Bавтоматически не является другом класса A.
  • Дружба не транзитивна  : если класс Aявляется другом класса B, а класс Bявляется другом класса C, класс Aавтоматически не является другом класса C.
  • Дружба не наследуется  — если класс Baseявляется другом класса X, подкласс Derivedне является автоматически другом класса X; и если класс Xявляется другом класса Base, класс Xавтоматически не является другом подкласса Derived. Однако, если класс Yявляется другом подкласса Derived, класс Yтакже будет иметь доступ к защищенным частям класса Base, как Derivedэто делает подкласс.

Смотрите также

использованная литература

внешняя ссылка