Pensar en C++ (Volumen 1) - Grupo ARCO
Pensar en C++ (Volumen 1) - Grupo ARCO Pensar en C++ (Volumen 1) - Grupo ARCO
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 244 — #282 ✐ Capítulo 8. Constantes Ni los constructores ni los destructores pueden ser métodos constantes porque prácticamente siempre realizan alguna modificación en el objeto durante la inicialización o la terminación. El miembro quote() tampoco puede ser constante porque modifica el atributo lastquote (ver la sentencia de retorno). Por otra parte lastQuote() no hace modificaciones y por eso puede ser const y puede ser llamado de forma segura por el objeto constante cq. mutable: constancia binaria vs. lógica ¿Qué ocurre si quiere crear un método constante, pero necesita cambiar algún atributo del objeto Esto se aplica a veces a la diferencia entre constante binaria (bitwise) y constante lógica (llamado también constante memberwise). Constante binaria significa que todos los bits del objeto son permanentes, así que la imagen binaria del objeto nunca cambia. Constante lógica significa que, aunque el objeto completo es conceptualmente constante puede haber cambios a nivel de miembro. Si se informa al compilador que un objeto es constante, cuidará celosamente el objeto para asegurar constancia binaria. Para conseguir constancia lógica, hay dos formas de cambiar los atributos con un método constante. La primera solución es la tradicional y se llama constancia casting away. Esto se hace de un modo bastante raro. Se toma this (la palabra que inidica la dirección del objeto actual) y se moldea el puntero a un puntero a objeto de la clase actual. Parece que this ya es un puntero válido. Sin embargo, dentro de un método constante, this es en realidad un puntero constante, así que moldeándolo a un puntero ordinario se elimina la constancia del objeto para esta operación. Aquí hay un ejemplo: //: C08:Castaway.cpp // "Casting away" constness class Y { int i; public: Y(); void f() const; }; Y::Y() { i = 0; } void Y::f() const { //! i++; // Error -- const member function ((Y*)this)->i++; // OK: cast away const-ness // Better: use C++ explicit cast syntax: (const_cast(this))->i++; } int main() { const Y yy; yy.f(); // Actually changes it! } ///:~ Esta aproximación funciona y puede verse en código correcto, pero no es la técnica ideal. El problema es que esta falta de constancia está oculta en la definición de un método y no hay ningún indicio en la interfaz de la clase que haga sospechar que ese dato se modifica a menos que puede accederse al código fuente (buscando el molde). Para poner todo al descubierto se debe usar la palabra mutable en la de- 244 ✐ ✐ ✐ ✐
✐ ✐ ✐ “Volumen1” — 2012/1/12 — 13:52 — page 245 — #283 ✐ 8.5. Volatile claración de la clase para indicar que un atributo determinado se puede cambiar aún perteneciendo a un objeto constante. //: C08:Mutable.cpp // The "mutable" keyword class Z { int i; mutable int j; public: Z(); void f() const; }; Z::Z() : i(0), j(0) {} void Z::f() const { //! i++; // Error -- const member function j++; // OK: mutable } int main() { const Z zz; zz.f(); // Actually changes it! } ///:~ De este modo el usuario de la clase puede ver en la declaración qué miembros tienen posibilidad de ser modificados por un método. ROMability Si un objeto se define como constante es un candidato para ser almacenado en memoria de sólo lectura (ROM), que a menudo es una consideración importante en programación de sistemas empotrados. Para conseguirlo no es suficiente con que el objeto sea constante, los requisitos son mucha más estrictos. Por supuesto, el objeto debe ser una constante binaria. Eso es fácil de comprobar si la constancia lógica se implementa mediante el uso de mutable, pero probablemente el compilador no podrá detectarlo si se utiliza la técnica del moldeado dentro de un método constante. Además: La clase o estructura no puede tener constructores o destructor definidos por el usuario. No pueden ser clases base (capitulo 14) u objetos miembro con constructores o destructor definidos por el usuario. El efecto de una operación de escritura en una parte del objeto constante de un tipo ROMable no está definido. Aunque un objeto pueda ser colocado en ROM de forma conveniente, no todos lo requieren. 8.5. Volatile La sintaxis de volatile es idéntica a la de const, pero volatile significa «este dato puede cambiar sin que el compilador sea informado de ello». De algún 245 ✐ ✐ ✐ ✐
- Page 231 and 232: ✐ ✐ ✐ “Volumen1” — 2012
- Page 233 and 234: ✐ ✐ ✐ “Volumen1” — 2012
- Page 235 and 236: ✐ ✐ ✐ “Volumen1” — 2012
- Page 237 and 238: ✐ ✐ ✐ “Volumen1” — 2012
- Page 239 and 240: ✐ ✐ ✐ “Volumen1” — 2012
- Page 241 and 242: ✐ ✐ ✐ “Volumen1” — 2012
- Page 243 and 244: ✐ ✐ ✐ “Volumen1” — 2012
- Page 245 and 246: ✐ ✐ ✐ “Volumen1” — 2012
- Page 247 and 248: ✐ ✐ ✐ “Volumen1” — 2012
- Page 249 and 250: ✐ ✐ ✐ “Volumen1” — 2012
- Page 251 and 252: ✐ ✐ ✐ “Volumen1” — 2012
- Page 253 and 254: ✐ ✐ ✐ “Volumen1” — 2012
- Page 255 and 256: ✐ ✐ ✐ “Volumen1” — 2012
- Page 257 and 258: ✐ ✐ ✐ “Volumen1” — 2012
- Page 259 and 260: ✐ ✐ ✐ “Volumen1” — 2012
- Page 261 and 262: ✐ ✐ ✐ “Volumen1” — 2012
- Page 263 and 264: ✐ ✐ ✐ “Volumen1” — 2012
- Page 265 and 266: ✐ ✐ ✐ “Volumen1” — 2012
- Page 267 and 268: ✐ ✐ ✐ “Volumen1” — 2012
- Page 269 and 270: ✐ ✐ ✐ “Volumen1” — 2012
- Page 271 and 272: ✐ ✐ ✐ “Volumen1” — 2012
- Page 273 and 274: ✐ ✐ ✐ “Volumen1” — 2012
- Page 275 and 276: ✐ ✐ ✐ “Volumen1” — 2012
- Page 277 and 278: ✐ ✐ ✐ “Volumen1” — 2012
- Page 279 and 280: ✐ ✐ ✐ “Volumen1” — 2012
- Page 281: ✐ ✐ ✐ “Volumen1” — 2012
- Page 285 and 286: ✐ ✐ ✐ “Volumen1” — 2012
- Page 287 and 288: ✐ ✐ ✐ “Volumen1” — 2012
- Page 289 and 290: ✐ ✐ ✐ “Volumen1” — 2012
- Page 291 and 292: ✐ ✐ ✐ “Volumen1” — 2012
- Page 293 and 294: ✐ ✐ ✐ “Volumen1” — 2012
- Page 295 and 296: ✐ ✐ ✐ “Volumen1” — 2012
- Page 297 and 298: ✐ ✐ ✐ “Volumen1” — 2012
- Page 299 and 300: ✐ ✐ ✐ “Volumen1” — 2012
- Page 301 and 302: ✐ ✐ ✐ “Volumen1” — 2012
- Page 303 and 304: ✐ ✐ ✐ “Volumen1” — 2012
- Page 305 and 306: ✐ ✐ ✐ “Volumen1” — 2012
- Page 307 and 308: ✐ ✐ ✐ “Volumen1” — 2012
- Page 309 and 310: ✐ ✐ ✐ “Volumen1” — 2012
- Page 311 and 312: ✐ ✐ ✐ “Volumen1” — 2012
- Page 313 and 314: ✐ ✐ ✐ “Volumen1” — 2012
- Page 315 and 316: ✐ ✐ ✐ “Volumen1” — 2012
- Page 317 and 318: ✐ ✐ ✐ “Volumen1” — 2012
- Page 319 and 320: ✐ ✐ ✐ “Volumen1” — 2012
- Page 321 and 322: ✐ ✐ ✐ “Volumen1” — 2012
- Page 323 and 324: ✐ ✐ ✐ “Volumen1” — 2012
- Page 325 and 326: ✐ ✐ ✐ “Volumen1” — 2012
- Page 327 and 328: ✐ ✐ ✐ “Volumen1” — 2012
- Page 329 and 330: ✐ ✐ ✐ “Volumen1” — 2012
- Page 331 and 332: ✐ ✐ ✐ “Volumen1” — 2012
✐<br />
✐<br />
✐<br />
“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 244 — #282<br />
✐<br />
Capítulo 8. Constantes<br />
Ni los constructores ni los destructores pued<strong>en</strong> ser métodos constantes porque<br />
prácticam<strong>en</strong>te siempre realizan alguna modificación <strong>en</strong> el objeto durante la inicialización<br />
o la terminación. El miembro quote() tampoco puede ser constante porque<br />
modifica el atributo lastquote (ver la s<strong>en</strong>t<strong>en</strong>cia de retorno). Por otra parte lastQuote()<br />
no hace modificaciones y por eso puede ser const y puede ser llamado<br />
de forma segura por el objeto constante cq.<br />
mutable: constancia binaria vs. lógica<br />
¿Qué ocurre si quiere crear un método constante, pero necesita cambiar algún<br />
atributo del objeto Esto se aplica a veces a la difer<strong>en</strong>cia <strong>en</strong>tre constante binaria (bitwise)<br />
y constante lógica (llamado también constante memberwise). Constante binaria<br />
significa que todos los bits del objeto son perman<strong>en</strong>tes, así que la imag<strong>en</strong> binaria del<br />
objeto nunca cambia. Constante lógica significa que, aunque el objeto completo es<br />
conceptualm<strong>en</strong>te constante puede haber cambios a nivel de miembro. Si se informa<br />
al compilador que un objeto es constante, cuidará celosam<strong>en</strong>te el objeto para asegurar<br />
constancia binaria. Para conseguir constancia lógica, hay dos formas de cambiar<br />
los atributos con un método constante.<br />
La primera solución es la tradicional y se llama constancia casting away. Esto se<br />
hace de un modo bastante raro. Se toma this (la palabra que inidica la dirección del<br />
objeto actual) y se moldea el puntero a un puntero a objeto de la clase actual. Parece<br />
que this ya es un puntero válido. Sin embargo, d<strong>en</strong>tro de un método constante, this<br />
es <strong>en</strong> realidad un puntero constante, así que moldeándolo a un puntero ordinario<br />
se elimina la constancia del objeto para esta operación. Aquí hay un ejemplo:<br />
//: C08:Castaway.cpp<br />
// "Casting away" constness<br />
class Y {<br />
int i;<br />
public:<br />
Y();<br />
void f() const;<br />
};<br />
Y::Y() { i = 0; }<br />
void Y::f() const {<br />
//! i++; // Error -- const member function<br />
((Y*)this)->i++; // OK: cast away const-ness<br />
// Better: use <strong>C++</strong> explicit cast syntax:<br />
(const_cast(this))->i++;<br />
}<br />
int main() {<br />
const Y yy;<br />
yy.f(); // Actually changes it!<br />
} ///:~<br />
Esta aproximación funciona y puede verse <strong>en</strong> código correcto, pero no es la técnica<br />
ideal. El problema es que esta falta de constancia está oculta <strong>en</strong> la definición<br />
de un método y no hay ningún indicio <strong>en</strong> la interfaz de la clase que haga sospechar<br />
que ese dato se modifica a m<strong>en</strong>os que puede accederse al código fu<strong>en</strong>te (buscando<br />
el molde). Para poner todo al descubierto se debe usar la palabra mutable <strong>en</strong> la de-<br />
244<br />
✐<br />
✐<br />
✐<br />
✐