¿Cuál es el significado de 'const' al final de una declaración de función miembro?
¿ Cuál es el significado de const
declaraciones como estas?
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Cuando agrega la const
palabra clave a un método, el this
puntero se convertirá esencialmente en un puntero a const
un objeto y, por lo tanto, no podrá cambiar ningún dato de miembro. (A menos que uses mutable
, hablaremos de eso más adelante).
La const
palabra clave es parte de la firma de funciones, lo que significa que puede implementar dos métodos similares, uno que se llama cuando el objeto es const
y otro que no lo es.
#include <iostream>
class MyClass
{
private:
int counter;
public:
void Foo()
{
std::cout << "Foo" << std::endl;
}
void Foo() const
{
std::cout << "Foo const" << std::endl;
}
};
int main()
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
}
Esto generará
Foo
Foo const
En el método no constante puedes cambiar los miembros de la instancia, lo que no puedes hacer en la const
versión. Si cambia la declaración del método en el ejemplo anterior al código siguiente, obtendrá algunos errores.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
Esto no es completamente cierto, porque puede marcar un miembro como mutable
y const
luego un método puede cambiarlo. Se usa principalmente para contadores internos y esas cosas. La solución para eso sería el siguiente código.
#include <iostream>
class MyClass
{
private:
mutable int counter;
public:
MyClass() : counter(0) {}
void Foo()
{
counter++;
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; // This works because counter is `mutable`
std::cout << "Foo const" << std::endl;
}
int GetInvocations() const
{
return counter;
}
};
int main(void)
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}
que daría salida
Foo
Foo const
Foo has been invoked 2 times
La constante significa que el método promete no alterar ningún miembro de la clase. Podrías ejecutar los miembros del objeto que están así marcados, incluso si el objeto en sí estuviera marcado const
:
const foobar fb;
fb.foo();
sería legal.
Consulte ¿Cuántos y cuáles son los usos de "const" en C++? para más información.
El const
calificador significa que los métodos se pueden invocar con cualquier valor de foobar
. La diferencia surge cuando consideras llamar a un método no constante en un objeto constante. Considere si su foobar
tipo tenía la siguiente declaración de método adicional:
class foobar {
...
const char* bar();
}
El método bar()
no es constante y solo se puede acceder a él desde valores no constantes.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
Sin embargo , la idea detrás const
es marcar métodos que no alterarán el estado interno de la clase. Este es un concepto poderoso pero en realidad no se puede aplicar en C++. Es más una promesa que una garantía. Y uno que a menudo se rompe y se rompe fácilmente.
foobar& fbNonConst = const_cast<foobar&>(fb1);
Estas constantes significan que el compilador generará un error si el método 'con const' cambia los datos internos.
class A
{
public:
A():member_()
{
}
int hashGetter() const
{
state_ = 1;
return member_;
}
int goodGetter() const
{
return member_;
}
int getter() const
{
//member_ = 2; // error
return member_;
}
int badGetter()
{
return member_;
}
private:
mutable int state_;
int member_;
};
La prueba
int main()
{
const A a1;
a1.badGetter(); // doesn't work
a1.goodGetter(); // works
a1.hashGetter(); // works
A a2;
a2.badGetter(); // works
a2.goodGetter(); // works
a2.hashGetter(); // works
}
Lee esto para más información
La respuesta de Blair es acertada.
Sin embargo, tenga en cuenta que hay un mutable
calificador que se puede agregar a los miembros de datos de una clase. Cualquier miembro así marcado puede modificarse en un const
método sin violar el const
contrato.
Es posible que desee utilizar esto (por ejemplo) si desea que un objeto recuerde cuántas veces se llama a un método en particular, sin afectar la consistencia "lógica" de ese método.