Creo en las funciones gratuitas y estoy de acuerdo con Sutter, pero mi entendimiento es en la dirección opuesta. No es que deba hacer que sus métodos públicos dependan de funciones gratuitas en lugar de métodos privados, sino que puede construir una interfaz más rica fuera de la clase con funciones gratuitas mediante el uso de la interfaz pública proporcionada.
Es decir, no empuja sus partes privadas fuera de la clase, sino que reduce la interfaz pública al mínimo que le permite construir el resto de la funcionalidad con el menor acoplamiento posible: solo utilizando la interfaz pública.
En su ejemplo, lo que movería fuera de la clase es el método CalculateDifference si se puede representar efectivamente en términos de otras operaciones.
class Number { // small simple interface: accessor to constant data, constructor
public:
explicit Number(int nNumber) : m_nNumber(nNumber) {}
int value() const { return m_nNumber; }
private:
int m_nNumber;
};
Number operator+(Number const & lhs, Number const & rhs) // Add addition to the interface
{
return Number(lhs.value() + rhs.value());
}
Number operator-(Number const & lhs, Number const & rhs) // Add subtraction to the interface
{
return Number(lhs.value() - rhs.value());
}
La ventaja es que si decide volver a definir sus componentes internos numéricos (no hay mucho que se puede hacer con una clase tan simple), siempre y cuando se mantenga su interfaz pública constante, entonces todas las demás funciones se trabajar fuera de la caja. Los detalles internos de implementación no lo forzarán a redefinir todos los otros métodos.
La parte difícil (no en el ejemplo simplista anterior) es determinar cuál es la menor interfaz que debe proporcionar. El artículo (GotW#84), al que se hace referencia a partir de una pregunta anterior, es un excelente ejemplo. Si lo lee en detalle, encontrará que puede reducir en gran medida la cantidad de métodos en std :: basic_string, manteniendo la misma funcionalidad y rendimiento. El conteo bajaría de 103 funciones miembro a solo 32 miembros. Eso significa que los cambios de implementación en la clase afectarán solo a 32 en lugar de a 103 miembros y, a medida que se mantenga la interfaz, las 71 funciones gratuitas que pueden implementar el resto de la funcionalidad en términos de los 32 miembros no tendrán que cambiarse.
Ese es el punto importante: está más encapsulado ya que limita el impacto de los cambios de implementación en el código.
Al salir de la pregunta original, aquí hay un ejemplo simple de cómo el uso de funciones gratuitas mejora la ubicación de los cambios en la clase. Supongamos una clase compleja con una operación de adición realmente compleja.Se podía ir a por ello y poner en práctica todas las anulaciones de operador como funciones miembro, o simplemente puede poner en práctica con la misma facilidad y eficacia sólo algunos de ellos internamente y proporcionar el resto como funciones gratuitas:
class ReallyComplex
{
public:
ReallyComplex& operator+=(ReallyComplex const & rhs);
};
ReallyComplex operator+(ReallyComplex const & lhs, ReallyComplex const & rhs)
{
ReallyComplex tmp(lhs);
tmp += rhs;
return tmp;
}
Se puede ver fácilmente que ningún importa cómo el original operator+=
realiza su tarea, el operator+
libre realiza su deber correctamente. Ahora, con todos y cada uno de los cambios a la clase, se deberá actualizar operator+=
, pero el operator+
externo permanecerá intacto por el resto de su vida útil.
El código anterior es un patrón común, mientras que por lo general en lugar de recibir la lhs
operando por referencia constante y la creación de un objeto temporal dentro, que puede ser cambiado para que el parámetro es en sí mismo una copia valor, ayudando al compilador con algunas optimizaciones :
ReallyComplex operator+(ReallyComplex lhs, ReallyComplex const & rhs)
{
lhs += rhs;
return lhs;
}
"¿Debería significar que debería tomar métodos privados y convertirlos en funciones de no amigos no miembros?" él está hablando de funciones públicas. es decir, la interfaz, no los detalles de implementación, como dijo la respuesta de Daniel, antes de que se lo quitara (¿por qué?) –
Este artículo de scott meyers lo explica en profundidad: http://www.ddj.com/cpp/184401197 –