Un uso típico es otorgar acceso a funciones que forman parte de la interfaz de la clase, pero gracias a otras reglas realmente no puede ser parte de la clase propiamente dicha. Los insertadores / extractores para iostreams son un ejemplo clásico:
namespace whatever {
class something {
// ...
friend std::ostream &operator<<(std::ostream &os, something const &thing);
friend std::istream &operator>>(std::istream &is, something &thing);
};
}
Hacer que estos operadores sean miembros de la clase no funcionará. Una operación de E / S se parece a:
whatever::something thing;
std::cout << thing;
Para un operador implementado como una función miembro, esto se resolvería como:
std::cout.operator<<(thing);
Es decir, la función debería ser miembro de std::cout
, no de something
. Como no queremos modificar std::ostream
constantemente, nuestra única opción razonable es sobrecargar al operador con una función libre en lugar de una función miembro. Eso nos deja con dos posibilidades: ignorar la encapsulación por completo y hacer que todo en la clase sea público, o mantenerlo privado, pero otorgar acceso a las pocas cosas que realmente lo necesitan.
Hacer que otra clase sea amiga es bastante menos común. En este caso, normalmente está creando algo en el orden de un módulo o subsistema: un conjunto de clases que funcionan juntas y tienen cierto grado de acceso especial entre sí que no se otorga al mundo en general.