Funzioni e Classi Friend

Funzioni "Amiche" (Friend)

Come abbiamo visto non possiamo accedere a membri privati di una classe dall'esterno della classe. Ma a volte abbiamo bisogno di farlo. Per esempio, una funzione di callback ha un header prestabilito, e non può essere il membro di nessuna classe. In questi casi, puoi definire la funzione come "friend" della classe. Così dall'interno della funzione sarai in grado di accedere a qualsiasi membro privato senza ottenere errori. Vediamo un esempio:
class A
{
  int a;
public:
  A (int aa) : a (aa) {}     // Costruttore che inizializza a
  friend void foo();
};

void foo()
{
  A a_obj (5);       // Normale chiamata
  a_obj.a = 10;      // Non sarebbe permesso in una funzione non-friend
}
Puoi mettere le dichiarazioni friend da qualsiasi parte nella definizione della classe, perchè una ad una funzione friend non si applicano gli attributi di pubblico o privato. Notare che è la classe che sceglie quali funzioni avranno il permesso di accedere direttamente ai suoi membri privati. Dopo questa dichiarazione nella classe, non è necessario alcun altro prototipo quando definiamo la funzione.

Le funzioni Friend sono spesso usate ridefinire gli operatori.

Una funzione friend non può accedere al puntatore this, perchè non viene invocata su un oggetto.

Puoi usare anche una funzione membro di un'altra classe come funzione friend di una classe.

class B;     // dichiarazione necessaria per evitare problemi di riferimento circolare
class A
{
  void uses_class_B (B &);             // Normale funzione membro
};
class B
{
  friend void A::uses_class_B (B &);   // dichiarazione di una funzione friend
};
In questo esempio la funzione uses_class_B della classe A, che accetta per parametro un riferimento ad un oggetto della classe B, è friend della classe B.

Classi Friend (o "Amiche")

Come abbiamo fatto per le funzioni, possiamo anche dichiarare delle classe friend. Questo è piuttosto semplice da fare:
class A
{
  int a;

  friend class B;
};
class B
{
public:
  void foo();
};
B::foo()
{
  A a_obj;
  a_obj.a = 10;          // Non sarebbe permesso se la classe B non fosse friend di A
}
Nota bene che è la classe A che sceglie quali classi hanno il diritto di accedere ai suoi membri privati e non quest'ultime.

Una conseguenza di questo fatto è che classi amiche di classi amiche di una classe non sono classi amiche anche di quest'ultima. Vediamo un esempio per chiarire il gioco di parole:

class A
{
  int a;
  friend class B;
};
class B
{
  int b;
  friend class C;
};
class C
{
  int c;
  int foo()
  {
    B b_obj;
    b_obj.b = 10;         // OK
    A a_obj;
    a_obj.a = 10;         // Rifiutata dal compilatore. Dovrebbe esserci
  }                       // una dichiarazione di C come class friend in A.
};
In altre parole la relazione X è friend di Y non è una relazione transitiva.

C è friend di B, B è friend di A non implica che C sia friend di A


C++