[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