You are on page 1of 7

8.4.3. Objetos y mtodos constantes Las funciones miembro (mtodos) se pueden hacer constantes. Qu significa eso?

Para entenderlo, primero debe comprender el concepto de objeto constante. Un objeto constante se define del mismo modo para un tipo definido por el usuario que para un tipo del lenguaje. Por ejemplo:

const int i = 1; const blob b(2);

Aqu, b es un objeto constante de tipo blob, su constructor se llama con un 2 como argumento. Para que el compilador imponga que el objeto sea constante, debe asegurar que el objeto no tiene atributos que vayan a cambiar durante el tiempo de vida del objeto. Puede asegurar fcilmente que los atributos no pblicos no sean modificables, pero. Cmo puede saber que mtodos cambiarn los atributos y cules son seguros para un objeto constante? Si declara un mtodo como constante, le est diciendo que la funcin puede ser invocada por un objeto constante. Un mtodo que no se declara constante se trata como uno que puede modificar los atributos del objeto, y el compilador no permitir que un objeto constante lo utilice. Pero la cosa no acaba ah. Slo porque un mtodo afirme ser const no garantiza que actuar del modo correcto, de modo que el compilador fuerza que en la definicin del mtodo se reitere el especificador const (la palabra const se convierte en parte del nombre de la funcin, as que tanto el compilador como el enlazador comprobarn que no se viole la constancia). De este modo, si durante la definicin de la funcin se modifica algn miembro o se llama algn mtodo no constante, el compilador emitir un mensaje de error. Por eso, est garantizado que los miembros que declare const se comportarn del modo esperado. Para comprender la sintaxis para declarar mtodos constantes, primero debe recordar que colocarconst delante de la declaracin del mtodo indica que el valor de retorno es constante, as que no produce el efecto deseado. Lo que hay que hacer es colocar el especificador const despus de la lista de argumentos. Por ejemplo:

//: C08:ConstMember.cpp class X { int i; public: X(int ii); int f() const;

};

X::X(int ii) : i(ii) {} int X::f() const { return i; }

int main() { X x1(10); const X x2(20); x1.f(); x2.f(); } ///:~

Listado 8.14. C08/ConstMember.cpp

La palabra const debe incluirse tanto en la declaracin como en la definicin del mtodo o de otro modo el compilador asumir que es un mtodo diferente. Como f() es un mtodo constante, si intenta modificar i de alguna forma o llamar a otro mtodo que no sea constante, el compilador informar de un error. Puede ver que un miembro constante puede llamarse tanto desde objetos constantes como desde no constantes de forma segura. Por ello, debe saber que esa es la forma ms general para un mtodo (a causa de esto, el hecho de que los mtodos no sean const por defecto resulta desafortunado). Un mtodo que no modifica ningn atributo se debera escribir como constante y as se podra usar desde objetos constantes. Aqu se muestra un ejemplo que compara mtodos const y mtodos ordinarios:

//: C08:Quoter.cpp // Random quote selection #include <iostream> #include <cstdlib> // Random number generator #include <ctime> // To seed random generator using namespace std;

class Quoter { int lastquote; public: Quoter(); int lastQuote() const; const char* quote(); };

Quoter::Quoter(){ lastquote = -1; srand(time(0)); // Seed random number generator }

int Quoter::lastQuote() const { return lastquote; }

const char* Quoter::quote() { static const char* quotes[] = { "Are we having fun yet?", "Doctors always know best", "Is it ... Atomic?", "Fear is obscene", "There is no scientific evidence " "to support the idea " "that life is serious", "Things that make us happy, make us wise",

}; const int qsize = sizeof quotes/sizeof *quotes; int qnum = rand() % qsize; while(lastquote >= 0 && qnum == lastquote) qnum = rand() % qsize; return quotes[lastquote = qnum]; }

int main() { Quoter q; const Quoter cq; cq.lastQuote(); // OK //! cq.quote(); // Not OK; non const function

for(int i = 0; i < 20; i++) cout << q.quote() << endl; } ///:~

Listado 8.15. C08/Quoter.cpp

Ni los constructores ni los destructores pueden ser mtodos constantes porque prcticamente siempre realizan alguna modificacin en el objeto durante la inicializacin o la terminacin. 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 consty puede ser llamado de forma segura por el objeto constante cq.
mutable: constancia binaria vs. lgica

Qu ocurre si quiere crear un mtodo constante, pero necesita cambiar algn atributo del objeto? Esto se aplica a veces a la diferencia entre constante binaria (bitwise) y constante lgica (llamado tambin constante memberwise). Constante binaria significa que todos los bits del objeto son permanentes, as que la imagen binaria del objeto nunca cambia. Constante lgica 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 lgica, hay dos formas de cambiar los atributos con un mtodo constante.

La primera solucin 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 direccin del objeto actual) y se moldea el puntero a un puntero a objeto de la clase actual. Parece que this ya es un puntero vlido. Sin embargo, dentro de un mtodo constante, this es en realidad un puntero constante, as que moldendolo a un puntero ordinario se elimina la constancia del objeto para esta operacin. 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<Y*>(this))->i++; }

int main() { const Y yy; yy.f(); // Actually changes it! } ///:~

Listado 8.16. C08/Castaway.cpp

Esta aproximacin funciona y puede verse en cdigo correcto, pero no es la tcnica ideal. El problema es que esta falta de constancia est oculta en la definicin de un mtodo y no hay ningn indicio en la interfaz de la clase que haga sospechar que ese dato se modifica a menos que puede accederse al cdigo fuente (buscando el molde). Para poner todo al descubierto se debe usar la palabra mutable en la declaracin de la clase para indicar que un atributo determinado se puede cambiar an 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! } ///:~

Listado 8.17. C08/Mutable.cpp

De este modo el usuario de la clase puede ver en la declaracin qu miembros tienen posibilidad de ser modificados por un mtodo.
ROMability

Si un objeto se define como constante es un candidato para ser almacenado en memoria de slo lectura (ROM), que a menudo es una consideracin importante en programacin de sistemas empotrados. Para conseguirlo no es suficiente con que el objeto sea constante, los requisitos son mucha ms estrictos. Por supuesto, el objeto debe ser una constante binaria. Eso es fcil de comprobar si la constancia lgica se implementa mediante el uso de mutable, pero probablemente el compilador no podr detectarlo si se utiliza la tcnica del moldeado dentro de un mtodo constante. Adems:

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 operacin 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.

You might also like