L'ultimo caso che prenderemo in considerazione per quel che riguarda i metodi delle classi è quello della dichiarazione delle funzioni friend
. Una funzione così dichiarata non è propriamente un membro di classe, ma ha il privilegio di accedere a tutti i membri di classe (privati, protetti e pubblici) come se lo fosse.
In un linguaggio con chiara vocazione alla programmazione orientata agli oggetti, come il C++, questo particolare costrutto potrebbe apparire anomalo. In realtà ci sono dei casi, che per brevità non esauriremo in questo contesto, in cui l'uso di friend risulta più immediato e risolutivo, ed in ultima analisi più efficiente, dell'applicazione ferrea del paradigma OOP.
Per fare un esempio pratico, prendiamo il caso della ridefinizione di uno degli operatori di I/O della libreria <iostream>
per la classe Point2D riportato nel listato seguente:
// point2d.h
class Geometry::Point2D
{
...
friend std::ostream& operator<<(std::ostream& out, const Point2D& o); // public, protected o private non hanno effetto sui metodi friend
};
std::ostream& operator<<(std::ostream& out, const Point2D& p) {
return out << p.x << ", " << p.y;
}
// main.cpp
#include <iostream>
#include "point2d.h"
int main()
{
Point2D a(1, 2);
std::cout << a << std::endl;
return 0;
}
La funzione operator<<
non è un membro della classe Point2D, eppure può accedere ai suoi membri privati. L'uso del qualificatore friend
in questo caso consente di uniformare l'interfaccia di I/O della nostra classe allo standard senza violare il principio di incapsulamento. Infatti, anche se le funzioni friend
non sono membri di classe, la loro dichiarazione deve apparire nella definizione della classe. Questo ci consente di rimanere in totale controllo dell'interfaccia, rendendo impossibili alterazioni dall'esterno mediante la definizione di funzioni friend
.