c++ - stoi - ¿Qué puede cambiar un método ''const''?
string to long c++ (5)
Los métodos C ++ permiten que un calificador const
indique que el objeto no ha cambiado el objeto. Pero ¿qué significa eso? P.ej. Si las variables de la instancia son punteros, ¿significa que los punteros no se cambian, o también que la memoria a la que apuntan no se modifica?
Concretamente, aquí hay una clase de ejemplo mínima.
class myclass {
int * data;
myclass() {
data = new int[10];
}
~myclass() {
delete [] data;
}
void set(const int index) const {
data[index] = 1;
}
};
¿El método set
correctamente califica como const
? No cambia los data
variable miembro, pero sí cambia el contenido de la matriz.
¿Qué puede cambiar un método ''const''?
Sin desechar explícitamente la constancia, un método const
puede cambiar:
- miembros de datos
mutable
, y - cualquier dato al que la clase no tenga acceso
const
, independientemente de si esos datos son accesibles:- A través de variables miembro que son punteros o referencias,
- A través de punteros o referencias pasadas como parámetros de función,
- A través de punteros o referencias devueltas por funciones,
- directamente en el espacio de nombres o en la clase (para estáticas) que lo contiene.
Para los miembros de class
/ struct
/ tipo de union
, se basa en la constancia de sus funciones miembro para determinar qué operaciones deben permitirse. (También puede cambiar cualquier variable local no constante y parámetros por valor, pero sé que no es lo que le interesa).
Puede llamar a otros métodos const
que tendrán estas mismas habilidades y restricciones.
P.ej. Si las variables de la instancia son punteros, ¿significa que los punteros no se cambian, o también que la memoria a la que apuntan no se modifica?
Significa que los punteros no pueden ser cambiados (fácilmente / accidentalmente). No significa que la memoria apuntada a no pueda ser cambiada.
Lo que ha encontrado es la incorrección lógica de una función const
que cambia datos apuntados o referenciados conceptualmente propiedad del objeto. Como ha encontrado, el compilador no impone la corrección const
que puede querer o esperar aquí. Eso es un poco peligroso, pero significa que la constancia no necesita ser eliminada explícitamente para los punteros / referencias a otros objetos que se pueden cambiar como un efecto secundario de la función const
. Por ejemplo, un objeto de registro. (Por lo general, tales objetos no son "propiedad" lógicamente del objeto cuya función const
opera sobre ellos). El punto clave es que el compilador no puede distinguir de manera confiable el tipo de propiedad lógica que un objeto tiene sobre los datos señalados, por lo que tiene que adivinar de un modo u otro y permitir que el programador anule o no esté protegido por la constancia. C ++ renuncia a la protección.
Interesante, escuché que el lenguaje D de Walter Bright cambia este valor predeterminado, haciendo que los datos apuntados sean const
por defecto en las funciones const
. Eso me parece más seguro, aunque es difícil imaginar la frecuencia con la que uno terminaría necesitando eliminar expresamente la constancia para permitir los efectos secundarios deseados, y si eso se sentiría satisfactorio de manera precisa o molesto.
Básicamente, const
impide cambiar los valores de los miembros de la instancia de clase dentro de la función. Esto es útil para una interfaz más clara, pero plantea restricciones cuando se utiliza la herencia, por ejemplo. A veces es un poco engañoso (o mucho en realidad), como en el ejemplo que publicaste.
const
sería más apropiado para funciones Get
, donde es obvio que la persona que llama está leyendo un valor y no tiene intenciones de cambiar el estado del objeto. En este caso, querrá limitar las implementaciones heredadas y adherirse a la const
, para evitar confusiones y errores ocultos al utilizar el polimorfismo.
Por ejemplo
class A{
int i;
public:
virtual int GetI() {return i;};
}
class B : public A{
public:
int GetI() { i = i*2; return i;}; // undesirable
}
cambiando A a
virtual int GetI() const {return i;};
resuelve el problema
Const cuando se aplica a un método significa:
Esto significa que el state
del objeto no será cambiado por el método.
Esto significa que no se puede modificar ningún miembro que sea parte del estado de los objetos, ni tampoco se puede llamar a ninguna función que no sea constante.
Como esto se relaciona con los punteros. Significa que el puntero (si es parte del estado) no se puede cambiar. Pero el objeto al que apunta el puntero es parte de otro objeto, lo que significa que puede llamar a métodos sin costo en este objeto (ya que no es parte del estado de este objeto).
Hay dos aspectos a esta pregunta:
- ¿Qué significa
const
para el compilador? - ¿Cómo se aplica
const
cuando no puede ser validado por el compilador?
Pregunta 1
El primero es bastante simple. El compilador valida que no se modifiquen miembros de datos (a menos que estén calificados como mutable
). Valida esto recursivamente: para cualquier tipo definido por el usuario, comprueba que no se invocan métodos que no sean constantes. Para los tipos incorporados, se valida que no están asignados.
La transformación para los punteros es T*
a T*const
(puntero const), no const T*
(puntero a const). Esto significa que el compilador no valida que el objeto al que se apunta no se modifique. Obviamente, esto lleva a la pregunta 2.
Pregunta 2
¿Cómo se aplica const
cuando no es validado por el compilador? Significa lo que debería significar para tu aplicación. Esto se suele denominar constante lógica. Cuándo usar const
con respecto a la constancia lógica está subject a debate .
Más sucintamente, significa que el tipo de this
es const T *
inside const miembro de las funciones, donde T
es su clase, mientras que en funciones no calificadas es T *
.
Su set
métodos no cambia los data
, por lo que puede calificarse como const. En otras palabras, myclass::data
se accede como this->data
y es de tipo int * const
.