2011-07-05 22 views
8

Tengo dos preguntas relacionadas con C++:¿Cuál es el significado real de la palabra clave "this"?

En muchos libros de texto, la palabra clave this es un puntero al objeto llamando. ¿Correcto?

Como me gusta jugar con la codificación, escribí el siguiente código simple:

struct Base 
{ 
    void g(); 
    virtual void f(); 
}; 

void Base::f() { 
    cout << "Base::f()" << endl; 
} 

void Base::g() { 
    cout << "Base::g()" << endl; 
    cout << "sizeof(*this) : " << sizeof(*this) << endl; 
    this->f(); 
} 

struct Derived : public Base 
{ 
    int d; 
    void f(); 
}; 

void Derived::f() 
{ 
    cout << "Derived::f()" << endl; 
} 

int main() 
{ 
    Base a; 
    Derived b; 

    cout << "sizeof(a) : " << sizeof(a) << endl; 
    cout << "sizeof(b) : " << sizeof(b) << endl; 

    a.g(); 
    b.g(); 
} 

El código anterior produce la siguiente salida:

sizeof(a) : 4 
sizeof(b) : 8 
Base::g() 
sizeof(*this) : 4 
Base::f() 
Base::g() 
sizeof(*this) : 4 // why 4 bytes not 8 bytes????????? 
Derived::f() 

Si this está apuntando al objeto que llama, ¿Debería la segunda línea de sizeof(*this) imprimir 8 en lugar de 4 dado que el objeto que llama es b? ¿Qué está pasando realmente aquí? ¿Ha sido degradado this? !!!!

Si this se ha degradado al tipo Base, ¿cómo this->f() invoca la función correcta? Estoy realmente confundido.

+0

trate de añadir una llamada a sizeof (*) en este Derivado :: f(). Mira lo que pone. La llamada en Base :: g() no sabe que es parte de una subclase. En ese caso, * esto hace referencia legítima a Base, no Derivado. –

+0

y ¿cómo espera que 'sizeof (* this)' se evalúe en tiempo de compilación? No es diferente de 'sizeof (Base)'. –

Respuesta

12
void Base::g() { 
    cout << "Base::g()" << endl; 
    cout << "sizeof(*this) : " << sizeof(*this) << endl; 
    this->f(); 
} 

La distinción importante que hay que hacer es que sizeof es un operador en tiempo de compilación, no un operador de tiempo de ejecución . El compilador interpreta la expresión sizeof(*this) como "el tamaño del objeto apuntado por this", que, en el ámbito de Base::g, sería un objeto del tipo Base. El compilador reescribir esencialmente que la declaración de este tipo, porque sabe que el tamaño de Base es de cuatro bytes:

cout << "sizeof(*this) : " << 4 << endl; 
+0

Oh, tienes razón. Modifiqué el código para imprimir el valor de 'this' en lugar de' sizeof (* this) 'y lo comparé con & b y & a. La respuesta coincidió con mis expectativas. Umhhh .. Graciasssssssss. – Eto700

0

this es un puntero de valor constante para el objeto que la función es un miembro no estático de. Lo que significa que, para que this sea un valor viable, debe usarse solo en miembros no estáticos de una clase. Recuerde: debe usar una instancia de objeto para llamar a una función miembro no estática (instancia.función o instancia-> función); this es un puntero a "instancia".

La razón por la que el tamaño nunca es el 8 que espera es porque g es miembro de la clase Base. Para g, this es del tipo Base *const, y por lo tanto *this es del tipo Base&. El sizeof(Base) es 4. Incluso si fuera un miembro virtual, esto no cambiaría; el tipo para esa implementación de g siempre sería Base *const. Las versiones prácticamente anuladas tendrían diferentes tipos, pero solo el tipo de la clase que las implementa.

this del tipo no sigue el polimorfismo; tiene exactamente y solo el tipo con el que se definió la función.

+0

Incluso si 'g' fuera virtual no importaría porque' g' nunca es anulada por la clase derivada, ¿no? –

+1

Solo para aclarar: incluso si 'g' fuera virtual,' sizeof (* this) 'siempre sería 4 en' Base :: g() 'independientemente de cómo se llamara a través de un tipo derivado (por ejemplo, si el virtual 'g()' no fue anulado). Sé que esto es lo que dices en tu última oración, pero el segundo párrafo podría dejar a los lectores pensando que 'sizeof (* this)' seguiría 'el tipo derivado incluso en la implementación base de 'g()'. –

1

Base no se puede ver/acceder/saber acerca de nada que sea parte de los objetos derivados, por lo que sizeof solo informa la parte del objeto que es visible para él. Más al punto, sizeof en un método de Base no puede saber que hay o habrá subclases (puede subclase Base sin recompilarlo, después de todo) por lo que no puede informar sobre nada que no sea la parte que conoce. (sizeof se calcula en tiempo de compilación, no en tiempo de ejecución).

0

Se llama a la función correcta f porque Base::f es virtual. Esto le dice al compilador que cuando se solicita una llamada al Base*->f(), se busca la dirección real del destinatario en el vtable del objeto real cuyo miembro usted invoca.

El tipo de la this en cuestión es Base*, que es la razón por sizeof(*this) == sizeof(Base), pero su vtable pertenece a un objeto derivado y por lo tanto la llamada de función a f va a la anulación.

Cuestiones relacionadas