estructuras - punteros c++
Tipo de puntero ''this'' (4)
Como mencioné en el título, me gustaría saber sobre el tipo de ''this''
puntero.
Estoy trabajando en un proyecto y observé que el tipo de puntero ''this''
es "ClassName * const this"
en Windows usando VC ++ 2008. Bueno, me gustaría saber cuál es la necesidad / requisito para hacer de este puntero una constante puntero. Gracias.
El tipo de este puntero es ClassName *
o const ClassName *
, dependiendo de si se inspecciona dentro de un método no const o const de la clase ClassName
. Puntero this
no es un valor l.
class ClassName {
void foo() {
// here `this` has `ClassName *` type
}
void bar() const {
// here `this` has `const ClassName *` type
}
};
La observación que mencionaste arriba es engañosa. Puntero this
no es un lvalue , lo que significa que no puede tener ClassName * const
type, es decir, no es posible tener un const
a la derecha de *
. Los valores no significativos del tipo de puntero no pueden ser const o non-const. Simplemente no hay tal concepto en el lenguaje C ++. Lo que observaste debe ser una peculiaridad interna del compilador específico. Formalmente, es incorrecto.
Aquí están las citas relevantes de la especificación del lenguaje (énfasis mío)
9.3.2 El puntero este
En el cuerpo de una función miembro no estática (9.3), la palabra clave this es una expresión prvalue cuyo valor es la dirección del objeto para el que se llama a la función. El tipo de esto en una función miembro de una clase X es X *. Si la función miembro se declara const, el tipo de esto es const X *, si la función miembro se declara volátil, el tipo de esto es volátil X *, y si la función miembro se declara const volátil, el tipo de esto es const volátil X *. [Nota: por lo tanto, en una función de miembro constante, se accede al objeto para el que se llama a la función a través de una ruta de acceso const. -Finalizar nota]
No vale la pena que en el C ++ 98 / C ++ 03 varios compiladores usaran un truco de implementación interno: interpretaron sus punteros como punteros constantes, por ejemplo, ClassName *const
en un método no constante de la clase ClassName
. Esto aparentemente les ayudó a asegurar la no modificabilidad de this
. Se sabe que GCC y MSVC usaron la técnica. Fue un truco inofensivo, ya que a nivel del lenguaje this
no era un valor y su constness era indetectable. Esa const
adicional generalmente se revelaría solo en los mensajes de diagnóstico emitidos por el compilador.
Sin embargo, con el advenimiento de referencias rvalue en C ++ 11, fue posible detectar esta const
adicional en el tipo de this
. Por ejemplo, el siguiente código es válido en C ++ 11
struct S
{
void foo() { S *&&r = this; }
};
Sin embargo, normalmente no se compilará en las implementaciones que aún utilizan el truco antes mencionado. GCC ha abandonado la técnica desde entonces. MSVC ++ todavía lo usa (a partir de VS2017), lo que impide que el código perfectamente válido anterior se compile en MSVC ++.
Hubo muchas discusiones arriba y la publicación principal no presentó la respuesta correcta. Es posible que las personas no escarban los comentarios, por lo que es mejor compartirlo como puerto principal (PS).
Hice algunas investigaciones en Ubuntu así como en VC ++ pero no hay salida correcta (usando typeid(X).name
).
El tipo de este puntero para una función miembro de un tipo de clase X es X * const. Si la función miembro se declara con el calificador const, el tipo de este puntero para esa función miembro para la clase X es const X * const. Enlace de MSDN
Conceptualmente esto también es correcto, porque la función de miembro normal es "X * const", por eso no es l-value (ya que no se puede cambiar su contenido).
La const significa que no puede cambiar a lo que apunta el puntero.
ClassName *const
es muy diferente de
const ClassName *
Este último es un puntero a un objeto y el objeto no puede ser modificado (usando el puntero, de todos modos). El primero es un puntero que no se puede volver a apuntar a otro objeto (ni NULL), al menos sin recurrir a la desagradable conversión.
Por supuesto, también existe la combinación:
const ClassName *const
Esto sería un puntero que no puede cambiarse para apuntar a otra cosa, ni puede usarse para cambiar el objeto al que apunta.
En cuanto a por qué su compilador muestra this
punteros como const, tiene sentido que se desanime de hacer this
punto a un objeto que no sea el que comenzó.
Un extracto de C ++ Primer 4th ed: "En una función ordinaria de miembro nonconst
, el tipo de this
es un const pointer
para el tipo de class
. Podemos cambiar el valor al cual this
apunta pero no podemos cambiar la dirección que this
contiene. función de miembro, el tipo de this
es un const pointer
a un objeto de tipo const class
. No podemos cambiar ni el objeto al que apunta ni la dirección que this
contiene ". Esto significa que todo lo que VC ++ intellisense estaba mostrando es correcto.