Fluidez de métodos

En C++ es común encontrar clases en las que necesitamos configurar o modificar un objeto mediante varias llamadas consecutivas. Para mejorar la legibilidad del código y evitar múltiples sentencias repetitivas, podemos emplear la fluidez de métodos (method chaining en inglés).

La idea es que cada método retorne una referencia al propio objeto (*this), de manera que podamos encadenar llamadas de forma natural.

Fundamento: return *this

En todo método no estático, el puntero this apunta al objeto actual. Si hacemos return *this;, devolvemos una referencia al mismo objeto que está recibiendo la llamada. Esto nos permite continuar aplicando métodos en cadena.

La firma típica de un método fluido es:

Tipo& metodo(...args) {
    // ...acciones sobre el objeto...
    return *this;
}

Para evitar copias innecesarias, se devuelve por referencia (Tipo&). Si el método no modifica el objeto, también puede devolverse por referencia constante (const Tipo&).

Ejemplo básico

#include <iostream>
#include <string>

class Cadena {
private:
    std::string texto;

public:
    // Método fluido: retorna una referencia al propio objeto
    Cadena& agregar(const std::string& s) {
        texto += s;
        return *this;
    }

    void imprimir() const {
        std::cout << texto << "\n";
    }
};

int main() {
    Cadena c;
    // Encadenamiento fluido
    c.agregar("Hola, ").agregar("mundo").agregar("!");
    c.imprimir();  // Imprime: Hola, mundo!
}

En este ejemplo, cada llamada a agregar devuelve una referencia a c, lo que permite encadenar varias operaciones sobre el mismo objeto en una sola instrucción.

Ejemplo práctico: configuración encadenada

Veamos un caso más realista: configurar la conexión a un servidor.

#include <iostream>
#include <string>

class Conexion {
private:
    std::string host;
    int puerto = 0;
    bool segura = false;

public:
    Conexion& setHost(const std::string& h) {
        host = h;
        return *this;
    }

    Conexion& setPuerto(int p) {
        puerto = p;
        return *this;
    }

    Conexion& usarSSL(bool s) {
        segura = s;
        return *this;
    }

    void conectar() const {
        std::cout << "Conectando a " << host << ":" << puerto
                  << (segura ? " con SSL\n" : " sin SSL\n");
    }
};

int main() {
    Conexion c;
    // Configuración fluida y expresiva
    c.setHost("localhost")
     .setPuerto(443)
     .usarSSL(true)
     .conectar();
}

Aquí, el objeto Conexion permite configurar de manera encadenada sus parámetros antes de ejecutar conectar(). Esto hace el código más claro y cercano a un lenguaje natural.