[C con Clase] estilo: Sobrecarga en funciones lectura escritura
Steven Davidson
srd4121 en njit.edu
Lun Mar 9 00:19:09 CET 2009
Hola Zaka,
Zakariae El-Abdelouarti wrote:
> Hola Steven,
>
> Tengo algunas preguntas sobre las respuestas a vicente lozano.
>
> El día 6 de marzo de 2009 19:19, Steven Davidson <srd4121 en njit.edu>
> escribió:
>> int x() const { return xv; }
>> int y() const { return yv; }
>>
>> Con esto, indicamos que las funciones son constantes que significa que éstas
>> no tienen intención alguna de modificar el estado de este objeto.
>
> ¿Por qué es necesario el operador const en estas declaraciones?¿De
> qué manera podrían las anteriores funciones modificar el estado del
> objeto?
>
Desde nuestro punto de vista, sabemos que estas funciones miembros no
modificarán el objeto, pero el compilador no lo sabe. Por ello,
establecemos que estas funciones miembros no modificarán el objeto para
que el compilador las tenga en cuenta. Esto implica que cuando manejemos
objetos constantes, podamos invocar estas funciones constantes. Por ejemplo,
class punto
{
private:
int xv;
int yv;
public:
punto( int vx=0, int vy=0 ) : xv(vx), yv(vy) {}
int x() { return xv; }
int y() { return yv; }
void x( int valor ) { xv=valor; }
void y( int valor ) { yv=valor; }
};
ostream &operator<<( ostream &os, const punto &pt )
{
return os << '(' << pt.x() << ',' << pt.y() << ')';
}
El compilador te marcará un error en la sobrecarga del operador <<
porque 'pt' es tratado como un objeto constante, pero estás usando
funciones miembros que no son constantes. El compilador no puede
asegurar la constancia del objeto 'pt' y por tanto da un error.
Si por el contrario, definimos la clase de esta manera, no tendremos tal
problema:
class punto
{
private:
int xv;
int yv;
public:
punto( int vx=0, int vy=0 ) : xv(vx), yv(vy) {}
int x() const { return xv; }
int y() const { return yv; }
void x( int valor ) { xv=valor; }
void y( int valor ) { yv=valor; }
};
Ahora 'x()' e 'y()' son funciones constantes y por tanto pueden ser
usadas con objetos constantes porque están aseguradas de no modificar el
objeto.
>> p.x() = 5;
>> p.y() = 10;
>
> Aquí supongo que estoy apelando a una de mis lagunas. Lo que hay a la
> izquierda de un operador de asignación de int -> int, ¿Es una
> variable?¿Es una dirección de memoria? ¿Puede ser cualquiera de las
> dos?
>
En general, se suele decir que lo que hay a la izquierda de un operador
de asignación es el llamado "lvalue" que en inglés se refiere a "left
value". Este "valor-i" debe ser una variable. A bajo nivel, ciertamente
la asignación usa la dirección de memoria de la variable. Por ejemplo,
int a;
a = 5;
Se traduciría en ensamblador como:
MOVE &a, 0x05
Por cierto, no estoy usando un lenguaje ensamblador específico; me lo he
inventado. Esto sólo es un ejemplo, pero muestra la necesidad de saber,
por parte del procesador, la dirección de memoria que será el destino de
guardar el valor de 5.
Obviamente, lo siguiente no tiene sentido en C/C++:
int a;
5 = a;
Si quisiéramos escribir esto directamente en ensamblador, el resultado
sería muy distinto:
MOVE 0x05, [a]
Posiblemente el procesador acabaría copiando el valor en 'a' en la
dirección de memoria 0x05. Lo más seguro que el sistema operativo se
verá forzado a terminar este programa de inmediato por haber violado el
área de memoria de otro programa.
En fin, el ejemplo que di a Vicente implica que esas funciones miembros
retornarían una referencia a la variable privada. Es decir,
p.x() = 5;
equivale al siguiente comportamiento:
p.xv = 5;
Espero haber aclarado las dudas.
Steven
Más información sobre la lista de distribución Cconclase