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 , klasa B nie jest automatycznie przyjaciółką klasy A.
  • Przyjaźnie nie są przechodnie – jeśli klasa A jest koleżanką klasy B , a klasa B jest koleżanką klasy C , to klasa A nie jest automatycznie przyjaciółką klasy C .
  • Przyjaźnie nie są dziedziczone – jeśli klasa Base jest przyjacielem klasy X , to podklasa Derived nie jest automatycznie przyjacielem klasy X ; a jeśli klasa X jest przyjacielem klasy Base , klasa X nie jest automatycznie przyjacielem podklasy Derived . Jeśli jednak klasa Y jest przyjacielem podklasy Derived , klasa Y będzie miała również dostęp do chronionych części klasy Base , tak jak ma to miejsce w przypadku podklasy Derived .

Zobacz też

Linki zewnętrzne