Класс друга в 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
это делает подкласс.