operador de asignación devolver una referencia a * esto en C ++

Leí sobre esto en “Effective c ++“, esto es Col.10. Dice que es una buena manera de que los operadores de asignación devuelvan una referencia a * esto. Escribí un fragmento de código para probar esta idea. He anulado el operador de asignación aquí. Y lo he probado. Todo esta bien. Pero cuando elimino la anulación de ese operador, todo es igual. Eso significa que la asignación de encadenamiento todavía funciona bien. Entonces, ¿qué me estoy perdiendo? ¿Porqué es eso? Necesito una explicación de ustedes, gracias.

#include  using namespace std; class Widget{ public: Widget& operator=(int rhs) { return *this; } int value; }; int main() { Widget mywidget; mywidget.value = 1; Widget mywidget2; mywidget2.value = 2; Widget mywidget3 ; mywidget3.value = 3; mywidget = mywidget2 = mywidget3; cout << mywidget.value<<endl; cout << mywidget2.value<<endl; cout << mywidget3.value<<endl; } 

Si elimina por completo el método operator= , el comstackdor creará un operator= predeterminado operator= , que implementa la copia superficial 1 y devuelve una referencia a *this .

Por cierto, cuando escribes

 mywidget = mywidget2 = mywidget3; 

en realidad está llamando a este operator= predeterminado operator= , ya que su operador sobrecargado está diseñado para trabajar con int s en el lado derecho.

La asignación encadenada dejará de funcionar, en cambio, si devuelve, por ejemplo, un valor, una referencia const (=> obtendrá errores de comstackción) o una referencia a algo diferente de *this (las cosas contraintuitivas comenzarán a suceder).

Parcialmente relacionado: el lenguaje de copia e intercambio , es decir, la forma perfecta de escribir un operador de asignación. Muy recomendable leer si necesitas escribir un operator=


  1. El operator= predeterminado operator= se realizará como si hubiera una asignación entre cada miembro del operando de la mano izquierda y cada miembro de la mano derecha. Esto significa que para los tipos primitivos será una copia bit a bit “brutal”, que en el 90% de los casos no está bien para los punteros a los recursos propios.

La pregunta toca dos conceptos diferentes, si debe definir operator= y si al hacerlo debe devolver una referencia al objeto.

Debe considerar la regla de los tres: si define uno de copia constructor , operador de asignación o destructor , debe definir los tres. El razonamiento en torno a esa regla es que si necesita proporcionar un destructor significa que está administrando un recurso y, al hacerlo, es probable que el constructor de copia y el operador de asignación predeterminados no lo eliminen. Como ejemplo, si mantiene la memoria a través de un puntero en bruto, necesita liberar la memoria en el destructor. Si no proporciona el constructor de copia y el operador de asignación , el puntero se copiará y dos objetos diferentes intentarán liberar la memoria contenida en el puntero.

Si bien un puntero es el ejemplo más común, esto se aplica a cualquier recurso. La excepción son las clases en las que deshabilitas la construcción y asignación de copias, pero de nuevo, de alguna manera, las estás definiendo como deshabilitadas .

En la segunda parte de la pregunta, o si debe devolver una referencia al objeto, debe hacerlo. La razón, al igual que con todas las sobrecargas de otros operadores, es que generalmente es un buen consejo para imitar lo que hacen los operadores existentes para los tipos básicos. Esto a veces viene dado por una cita: cuando se sobrecargan los operadores, haga lo que se int hacer .

Widget& operator=(int rhs)

Esto le permite asignar un int a un Widget, por ejemplo, mywidget = 3;

Haga un Widget& operator=(Widget const & rhs) – se llamará para su mywidget = mywidget2 = mywidget3; línea.

Sin embargo, no necesita un operator=(Widget const & rhs) : el valor predeterminado debería funcionar bien.

Además, puede ser una buena idea agregar, por ejemplo, cout << "operator=(int rhs)\n"; a su operador personalizado, entonces vería que no fue llamado en absoluto en su código.