Cuál es el significado de const
en declaraciones como estas?
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Esteras Fredriksson
Cuando agregas el const
palabra clave a un método el this
puntero se convertirá esencialmente en un puntero a const
objeto y, por lo tanto, no puede cambiar ningún dato de miembro. (A menos que utilice mutable
más sobre eso más adelante).
El const
La 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 uno 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 non-const puede cambiar los miembros de la instancia, lo que no puede hacer en el const
versión. Si cambia la declaración del método en el ejemplo anterior al código a continuación, 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 puedes marcar a un miembro como mutable
y un const
El 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
-
¿Qué pasa si solo hago un método const pero sin un método normal, y luego llamo al método usando un objeto que no es const? Mi código generalmente funciona bien. ¿Es malo o dañino o algo así?
– KhiemGOM
27 de agosto de 2021 a las 1:55
-
@KhiemGOM Eso está completamente bien, y es un patrón bastante normal para miembros de solo lectura.
–Mats Fredriksson
15 de noviembre de 2021 a las 19:11
-
mutable
yconst
tiene sentido para mi. Pero lo que no entiendo bien es que si unconst
A la función miembro le gustaría cambiar el valor de un miembro, ¿por qué no descartarlo?const
y convertirse en una función de miembro no const? ¿Tiene algo que ver con la velocidad? O es como dadas dos variables miembro, una tiene unmutable
palabra clave y otra no, en unconst
función miembro, nos gustaría cambiar solo el valor de la variable conmutable
palabra clave pero quiere mantener otra intacta?– León Lai
21 de febrero a las 11:21
Blair Conrado
La const significa que el método promete no alterar ningún miembro de la clase. Podría ejecutar los miembros del objeto que están marcados, incluso si el objeto mismo estuviera marcado const
:
const foobar fb;
fb.foo();
sería legal.
Ver ¿Cuántos y cuáles son los usos de “const” en C++? para más información.
jaredpar
El const
calificador significa que los métodos pueden ser llamados en cualquier valor de foobar
. La diferencia surge cuando considera llamar a un método no constante en un objeto constante. Considere si su foobar
type 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 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
}
La idea detrás const
aunque es para marcar métodos que no alterarán el estado interno de la clase. Este es un concepto poderoso, pero en realidad no se aplica 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);
-
Pensé que la respuesta es sobre otros métodos const y no sobre objetos const.
– Mykola Golubiev
15 de abril de 2009 a las 14:14
-
Gracias por “La idea detrás
const
aunque es para marcar métodos que no alterarán el estado interno de la clase”. Eso es realmente lo que estaba buscando.– kovac
17 de marzo de 2019 a las 9:01
-
@JaredPar, ¿significa esto que cualquier función miembro que represente una operación de solo lectura debe marcarse como
const
?– kovac
17 de marzo de 2019 a las 9:03
Mykola Golubiev
Estas const 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
}
Leer este para más información
La respuesta de Blair está en la marca.
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 poder modificarse en un const
método sin violar el const
contrato.
Es posible que desee usar esto (por ejemplo) si desea que un objeto recuerde cuántas veces se llama a un método en particular, sin afectar la constancia “lógica” de ese método.
Significado de una función miembro constante en C++ Common Knowledge: Essential Intermediate Programming da una explicación clara:
El tipo del puntero this en una función miembro no const de una clase X es X * const. Es decir, es un puntero constante a una X no constante (consulte Punteros constantes y Punteros a constantes). [7, 21]). Debido a que el objeto al que se refiere esto no es const, se puede modificar. El tipo de this en una función miembro const de una clase X es const X * const. Es decir, es un puntero constante a una constante X. Debido a que el objeto al que se refiere es const, no se puede modificar. Esa es la diferencia entre funciones miembro constantes y no constantes.
Así que en tu código:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Puedes pensarlo así:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
Me gustaría añadir el siguiente punto.
También puedes hacer es un const &
y const &&
Entonces,
struct s{
void val1() const {
// *this is const here. Hence this function cannot modify any member of *this
}
void val2() const & {
// *this is const& here
}
void val3() const && {
// The object calling this function should be const rvalue only.
}
void val4() && {
// The object calling this function should be rvalue reference only.
}
};
int main(){
s a;
a.val1(); //okay
a.val2(); //okay
// a.val3() not okay, a is not rvalue will be okay if called like
std::move(a).val3(); // okay, move makes it a rvalue
}
Siéntete libre de mejorar la respuesta. no soy un experto
-
*this
es siempre un lvalue, incluso si la función miembro es rvalue-ref-qualified y se llama en un rvalue. Ejemplo.– Santo Gato Negro
26/03/2019 a las 17:30
-
Actualizado. ¿Está bien?
– codificador3101
26 de marzo de 2019 a las 18:05