[C con Clase] ¿que significa la sentencia .....return *this

Steven Davidson srd4121 en njit.edu
Lun Sep 20 20:37:44 CEST 2010


Hola Wolverine,

On 9/20/2010 1:16 PM, wolverine_ch wrote:
>
> hola Steven Davidson...
>
> bueno entiendo casi todo pero la ultima parte me dices que la funcion
> retorna una refencia ala clase vector(por eso el signo asperson) ..,
> claro ..pero la funcion retorna un return*this
> osea una desreferencia al objeto y por lo tanto su tipo de retorno
> deberia ser tambien una desrefencia al objeto como es logico y para
> ello se usa el signo asterisco:
>
> vector* vector:: operator + (vector P)
>

Creo que te estás liando con el carácter *. En C/C++, el símbolo * tiene 
tres funciones:

1. Operador binario de multiplicación. Por ejemplo,

5 * 3

2. Operador unitario de "desreferencia" de un puntero, que significa que 
accedemos a una variable - y a su valor - apuntada por el puntero. Por 
ejemplo,

*ptr = 10;

cout << *ptr << endl;

3. Declarador (unitario) para indicar el tipo de dato como un puntero a 
otro tipo. Por ejemplo,

int *ptr;


Para aclarar la duda que estás teniendo, nos interesa las dos últimas 
funciones, que básicamente tratan de la dualidad del asterisco. En el 
#2, el asterisco actúa como un operador accediendo a una variable y en 
el #3 el asterisco actúa como un declarador. Un declarado es parecido a 
un operador: las reglas de precedencia y asociatividad se mantienen, 
pero no opera sino que sirve para formar parte de una declaración 
indicando el tipo de dato.

Al escribir:

return *this;

Estamos usando el asterisco en su función de operador: accedemos a la 
variable apuntado por 'this'. Como cada variable tiene su propio tipo de 
dato asociado a ella, porque C/C++ son lenguajes fuertemente 
tipificados, entonces tenemos que asegurar que el tipo de dato de la 
variable "desreferenciada" coincida con el tipo de dato de retorno de 
esta función. Si no existe una coincidencia directa, entonces se 
permiten promociones: cástings implícitos.

Como 'this' apunta a sí mismo, dependiendo del ámbito en el que estemos, 
podemos deducir fácilmente el tipo de dato apuntado. En el ejemplo, se 
trata del tipo 'vector'. Por lo tanto, retornamos un objeto de la clase 
'vector'. Podríamos haber hecho esto:

vector vector::operator+( vector P )
{
   ...
   return *this;
}

Sin embargo, hay que tener en cuenta que al retornar un dato, éste es 
copiado. Para los tipos fundamentales, no tenemos mayor inconveniente 
que se copie al retornarlo, pero en este caso estamos retornando un 
objeto. Esto significa que se instancia un objeto temporal solamente 
para retornarlo. En general, es costoso retornar un objeto, pero también 
puede ir en contra de nuestro diseño. Si queremos el mismo objeto que 
hemos usado en esta función, recibir una copia de ello no nos sirve.

Como C++ permite crear referencias, no solamente podemos pasar datos por 
referencia, sino también nos sirve para retornar datos por referencia. 
Esto es justo lo que estamos haciendo en este ejemplo. Retornamos una 
referencia al objeto apuntado.

Nuevamente, el símbolo & tiene varias funciones en el lenguaje de C++, 
que son:

1. Operador binario a nivel de bits que representa la operación AND. Por 
ejemplo,

10 & 3

2. Operador unitario de referencia para lograr la dirección de memoria 
de una variable. Por ejemplo,

int num = 10;
int *ptr = #

3. Declarador (unitario) para indicar que un tipo de dato es una 
referencia a otro tipo. Por ejemplo,

int num = 10;
int &ref = num;


Para el tipo de retorno de nuestra función, usamos 'vector &' para 
indicar que retornamos una referencia y no una copia del objeto de la 
clase 'vector', el cual fue obtenido accediendo a ello a través del 
puntero 'this'. Podemos ver esto reflejado en el código,

vector & vector::operator+( vector P )
{
   ...
   return *this;
}

La razón principal de retornar el objeto como referencia es para hacer 
otras operaciones con ella. Por ejemplo,

vec1 + vec2 + vec3;

Esto es igual que,

vec1.operator+( vec2 ).operator+( vec3 );

que viene a ser igual que esto:

(vec1.operator+( vec2 )).operator+( vec3 );


Personalmente, habría usado una referencia para el parámetro, 'P', por 
lo que sería,

vector & vector::operator+( const vector &P )
{
   x += P.x;
   y += P.y;

   return *this;
}

Así no tenemos que pasar un objeto por copia que puede ser costoso tanto 
en tiempo de ejecución como en memoria. A veces sí se necesita pasar 
objetos por copia, pero en este caso, no veo que pasarlo por referencia 
dañe el diseño.

Por último, me extraña que el operador sea +, ya que no tiene mucho 
sentido modificar el objeto cuando el operador es una suma. Sí tiene 
sentido si el operador fuese += ya que implica una asignación. Pero en 
fni, supongo que es un ejemplo, al fin y al cabo, y el diseñador hace lo 
que quiere.

> aclarame porfavor y disculpa mi terquedad jeje...
>

No te preocupes. A todos nos trae de cabeza el tema de los punteros. 
Incluso a veces los veteranos tienen problemas en seguir las 
indirecciones de los punteros.


Espero haber aclarado la duda.

Steven





Más información sobre la lista de distribución Cconclase