Класс друга - Friend class
А класс друзей в C ++ может получить доступ к частный и защищенный члены учебный класс в котором он объявлен другом.[1] Существенное использование дружественного класса - это часть структуры данных, представленная классом, для обеспечения доступа к основному классу, представляющему эту структуру данных. Механизм дружественного класса позволяет расширять хранилище и доступ к частям, сохраняя при этом надлежащую инкапсуляцию, которую видят пользователи структуры данных.
Подобно классу друзей, функция друга это функция которому предоставляется доступ к закрытым и защищенным членам класса, в котором он объявлен как друг.
Пример
В следующем примере демонстрируется использование дружественного класса для структуры данных графа, где граф представлен основным классом Graph, а вершины графа представлены классом Vertex.
#включают <iostream>#включают <memory>#включают <string>#включают <unordered_set>учебный класс График;учебный класс Вершина { общественный: явный Вершина(стандартное::нить имя) : края_(), имя_(стандартное::двигаться(имя)) {} авто начинать() const { возвращаться края_.cbegin(); } авто конец() const { возвращаться края_.уступать(); } const авто& имя() const { возвращаться имя_; } частный: // Vertex дает права доступа к Graph. друг учебный класс График; стандартное::unordered_set<Вершина*> края_; стандартное::нить имя_;};учебный класс График { общественный: ~График() { пока (!вершины_.пустой()) { авто вершина = вершины_.начинать(); RemoveVertex(*вершина); } } авто AddVertex(const стандартное::нить& имя) -> Вершина* { авто вершина = стандартное::make_unique<Вершина>(имя); авто iter = вершины_.вставлять(вершина.получать()); возвращаться вершина.релиз(); } пустота RemoveVertex(Вершина* вершина) { вершины_.стереть(вершина); Удалить вершина; } авто AddEdge(Вершина* из, Вершина* к) { // Graph может получить доступ к закрытым полям Vertex, потому что Vertex объявила Graph как // друг. из->края_.вставлять(к); } авто начинать() const { возвращаться вершины_.cbegin(); } авто конец() const { возвращаться вершины_.уступать(); } частный: стандартное::unordered_set<Вершина*> вершины_;};
Инкапсуляция
Правильное использование дружественных классов увеличивает инкапсуляцию, потому что оно позволяет расширить частный доступ структуры данных к ее частям, которыми структура данных владеет, без предоставления частного доступа любому другому внешнему классу. Таким образом, структура данных остается защищенной от случайных попыток взлома инвариантов структуры данных извне.
Важно отметить, что класс не может предоставить себе доступ к частной части другого класса; это нарушит инкапсуляцию. Скорее, класс предоставляет доступ к своим частным частям другому классу --- объявляя этот класс своим другом. В примере с графом Graph не может объявить себя другом Vertex. Вместо этого Vertex объявляет Graph своим другом и тем самым предоставляет Graph доступ к своим частным полям.
Тот факт, что класс выбирает себе друзей, означает, что дружба в целом несимметрична. В примере с графом Vertex не может получить доступ к закрытым полям Graph, хотя Graph может получить доступ к закрытым полям Vertex.
Альтернативы
Похожая, но не эквивалентная функция языка предоставляется ключевым словом C # internal, которое позволяет классам внутри одной сборки получать доступ к закрытым частям других классов. Это соответствует маркировке каждого класса как друга другого в той же сборке; дружеские классы более детализированы.
Языки программирования, в которых отсутствует поддержка дружественных классов или аналогичных языковых функций, должны будут реализовать обходные пути для достижения безопасного частичного интерфейса для структуры данных. Примеры таких обходных путей:
- Сделайте поля частей общедоступными. Это решение снижает инкапсуляцию, делая возможным нарушение инвариантов структуры данных извне.
- Переместите все изменяемые структурные данные из части в структуру данных и введите косвенное обращение от каждой части к ее структуре данных. Это решение изменяет организацию структуры данных и увеличивает потребление памяти в тех случаях, когда в противном случае в этой информации не было бы необходимости.
Характеристики
- Дружбы нет симметричный - если класс
А
классный другB
, учебный классB
не является автоматически другом классаА
. - Дружбы нет переходный - если класс
А
классный другB
, и классB
классный другC
, учебный классА
не является автоматически другом классаC
. - Дружбы нет унаследованный - если класс
Основание
классный другИкс
, подклассПолученный
не является автоматически другом классаИкс
; и если классИкс
классный другОснование
, учебный классИкс
не является автоматически другом подклассаПолученный
. Однако если классY
друг подклассаПолученный
, учебный классY
также будет иметь доступ к защищенным частям классаОснование
, так же как подклассПолученный
делает.