Primero hay que tener en claro qué significa la palabra reservada
this. Dicho de forma simplificada, es un puntero que apunta al objeto en sí, es decir, mantiene la dirección de memoria del objeto al que hace referencia. Cada objeto tiene una dirección de memoria, al igual que todo tipo primitivo como
int,
float,
etc. Esto puedes verlo más claro si imprimes el valor de
this y
&obj, donde
obj es un objeto de cualquier clase. En código se vería así:
class Foo
{
public:
void printDir()
{
std::printf("%X\n", this);
}
};
int main()
{
Foo obj;
obj.printDir();
std::printf("%X\n", &obj);
return 0;
}
Como verás, la salida es la misma. Pues resulta que esa palabra reservada es una forma cómoda de tener al alcance la dirección de memoria del objeto y así es posible hacer cosas como las que muestras en el ejemplo.
Stream Stream::operator<<(const char *s) {
printf(s);
return *this;
}
Al hacer
*this estás haciendo lo que se conoce como desreferenciar el puntero, es decir, accedes al objeto en sí, no a su dirección de memoria, por lo que al hacer
return *this y dado el tipo de devuelta de tu función, estás devolviendo una copia del objeto, lo cual no es lo más óptimo, ya que es una copia innecesaria. Ahí justo puedes devolver una referencia. Una referencia y un puntero son prácticamente el mismo concepto, salvo que la referencia tienes que inicializarla donde la defines, además si una función recibe una referencia, no usas el operador
&, sino únicamente el nombre del objeto, haciendo que el código se vea menos tedioso. También existe la desreferenciación automática, es decir, si fuera un puntero, harías
ptr-> para acceder a un campo o método, pero en una referencia usarías el
. como si fuera un objeto normal.
cout << "Hola" << "Adios" << "\n";
Esto funciona porque el primer
cout (es decir,
cout << "Hola" ) se convierte a un objeto, que es una copia del objeto original, después haces
<< "Adios", ahí sigues teniendo el objeto copia que ya imprimió hola, pero ahora estás llamando con ese objeto otra vez al operador
<< con el argumento
adiós, entonces lo imprimes y así sucesivamente. En resumen, al hacer
*this puedes realizar llamadas en cadena, que es lo que estás haciendo en tu código.
Otro ejemplo:
#include <iostream>
class Sum
{
public:
Sum& operator+(int val)
{
sum += val;
return *this;
}
int getSum()
{
return sum;
}
private:
int sum = 0;
};
int main()
{
Sum s;
s = s + 3 + 3 + 5 + 6;
std::cout << s.getSum() << "\n";
return 0;
}