Klasa przyjaciół
Przyjazna klasa w C ++ może uzyskiwać dostęp do prywatnych i chronionych członków klasy , w której została zadeklarowana jako przyjazna. Znaczącym zastosowaniem klasy zaprzyjaźnionej jest to, że część struktury danych, reprezentowana przez klasę, zapewnia dostęp do głównej klasy reprezentującej tę strukturę danych. Mechanizm klasy przyjaciół pozwala rozszerzyć przechowywanie i dostęp do części, zachowując przy tym odpowiednią enkapsulację widzianą przez użytkowników struktury danych.
Podobnie jak klasa przyjaciół, funkcja przyjaciół to funkcja , która ma dostęp do prywatnych i chronionych członków klasy, w której jest zadeklarowana jako przyjaciółka.
Przykład
Poniższy przykład ilustruje użycie klasy friend dla struktury danych grafu, gdzie graf jest reprezentowany przez główną klasę Graph, a wierzchołki grafu są reprezentowane przez klasę Vertex.
#include <iostream> #include <pamięć> #include <string> #include < nieuporządkowany_zbiór> class Graph ; class Vertex { public : explicit Vertex ( std :: string name ) : edge_ (), name_ ( std :: move ( name )) {} auto begin () const { return edge_ . początek (); } auto koniec () const { powrót krawędzie_ . cena (); } const auto & name () const { return nazwa_ ; } private : // Vertex nadaje prawa dostępu do Graph. wykres klasy przyjaciela ; std :: unordered_set < Wierzchołek *> krawędzie_ ; std :: ciąg nazwa_ ; }; class Graph { public : ~ Graph () { while ( ! wierzchołki_ . pusty ()) { auto wierzchołek = wierzchołki_ . rozpocząć (); Usuń wierzchołek ( * wierzchołek ); } } auto AddVertex ( const std :: string & name ) -> Vertex * { auto vertex = std :: make_unique < Vertex > ( name ); auto iter = wierzchołki_ . wstaw ( wierzchołek . pobierz ()); zwrotny wierzchołek . zwolnij (); } void Usuń wierzchołek ( wierzchołek * wierzchołek ) { wierzchołki_ . wymaż ( wierzchołek ); usuń wierzchołek ; } auto AddEdge ( Vertex * from , Vertex * to ) { // Graph może uzyskać dostęp do prywatnych pól Vertex, ponieważ Vertex zadeklarował Graph jako // znajomy. od -> krawędzie_ . wstaw ( do ); } auto begin () const { return wierzchołki_ . początek (); } auto koniec () const { powrót wierzchołków_ . cena (); } private : std :: unordered_set < Wierzchołek *> wierzchołki_ ; };
Kapsułkowanie
Właściwe użycie klas znajomych zwiększa enkapsulację, ponieważ pozwala rozszerzyć prywatny dostęp do struktury danych na jej części --- które posiada struktura danych --- bez zezwalania na prywatny dostęp jakiejkolwiek innej klasie zewnętrznej. W ten sposób struktura danych jest chroniona przed przypadkowymi próbami złamania niezmienników struktury danych z zewnątrz.
Należy zauważyć, że klasa nie może dać sobie dostępu do prywatnej części innej klasy; to złamałoby enkapsulację. Raczej klasa daje dostęp do swoich prywatnych części innej klasie --- deklarując tę klasę jako przyjaciela. W przykładzie wykresu Graph nie może zadeklarować się jako przyjaciel Vertex. Zamiast tego Vertex deklaruje Graph jako przyjaciela iw ten sposób zapewnia Graphowi dostęp do swoich prywatnych pól.
Fakt, że klasa wybiera swoich własnych przyjaciół, oznacza, że przyjaźń nie jest ogólnie symetryczna. W przykładzie wykresu Vertex nie może uzyskać dostępu do prywatnych pól Graph, chociaż Graph może uzyskać dostęp do prywatnych pól Vertex.
Alternatywy
Podobną, ale nie równoważną funkcję językową zapewnia wewnętrzne słowo kluczowe języka C#, które umożliwia klasom wewnątrz tego samego zestawu dostęp do części prywatnych innych klas. Odpowiada to oznaczeniu każdej klasy jako przyjaciela innej w tym samym zgromadzeniu; klasy przyjaciół są bardziej szczegółowe.
Języki programowania, które nie obsługują klas znajomych lub podobnych funkcji językowych, będą musiały wdrożyć obejścia, aby uzyskać bezpieczny, oparty na częściach interfejs do struktury danych. Przykładami takich obejść są:
- Upublicznij pola części. To rozwiązanie zmniejsza enkapsulację, umożliwiając naruszenie niezmienników struktury danych z zewnątrz.
- Przenieś wszystkie zmienne dane strukturalne z części do struktury danych i wprowadź przekierowanie z powrotem z każdej części do jej struktury danych. To rozwiązanie zmienia organizację struktury danych i zwiększa zużycie pamięci w przypadkach, gdy w przeciwnym razie informacje te nie byłyby potrzebne.
Nieruchomości
- Przyjaźnie nie są symetryczne – jeśli klasa
A
jest przyjaciółką klasy B,
klasaB
nie jest automatycznie przyjaciółką klasyA.
- Przyjaźnie nie są przechodnie – jeśli klasa
A
jest koleżanką klasyB
, a klasaB
jest koleżanką klasyC
, to klasaA
nie jest automatycznie przyjaciółką klasyC
. - Przyjaźnie nie są dziedziczone – jeśli klasa
Base
jest przyjacielem klasyX
, to podklasaDerived
nie jest automatycznie przyjacielem klasyX
; a jeśli klasaX
jest przyjacielem klasyBase
, klasaX
nie jest automatycznie przyjacielem podklasyDerived
. Jeśli jednak klasaY
jest przyjacielem podklasyDerived
, klasaY
będzie miała również dostęp do chronionych części klasyBase
, tak jak ma to miejsce w przypadku podklasyDerived
.
Zobacz też
Linki zewnętrzne
- http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr043.htm
- http://www.cplusplus.com/doc/tutorial/inheritance/