2010-06-09 13 views
7

Estuve recientemente en una entrevista para un puesto donde C/C++ es el idioma principal y durante una pregunta me dijeron que es posible usar el vtable para determinar qué clase en una jerarquía un puntero base en realidad almacena.Cómo usar el vtable para determinar el tipo de clase

Así que si, por ejemplo, que tienen

class A 
    { 
    public: 
    A() {} 
    virtual ~A() {} 
    virtual void method1() {} 
    }; 

    class B : public A 
    { 
    public: 
    B() {} 
    virtual ~B() {} 
    virtual void method1() {} 
    }; 

y se ejemplariza A * pFoo = new B(), ¿es realmente posible utilizar la viable para determinar si pFoo contiene un puntero a una instancia de A o B?

+0

Gracias por las respuestas. Olvidé mencionar que pregunté si RTTI era lo que estaban buscando, y dijeron que, en general, desactivan RTTI, así que no es así. Es muy posible que la solución que estaban buscando fuera lo que Martin B describió –

Respuesta

10

Esto obviamente depende de la implementación pero, en la mayoría de las implementaciones, la representación en memoria de un objeto de la clase A o B comenzará con un puntero al vtable. Puede ver este puntero vtable, compararlo con punteros vtable para objetos que sabe que son de la clase A o B, y determinar la clase del objeto de esa manera.

Para ilustrar (por supuesto, esto es cualquier cosa menos un buen estilo):

A *pFoo=new B(); // pointer to object of unknown class (either A or B) 
A a; // Object known to be of class A 
B b; // Object known to be of class B 
void *vptrA=*((void **)&a); // Pointer to vtable of class A 
void *vptrB=*((void **)&b); // Pointer to vtable of class B 
void *vptrFoo=*((void **)pFoo); // Pointer to vtable of unknown object 
if(vptrFoo==vptrA) 
    printf("Class A\n"); 
else 
    printf("Class B\n"); 

Importante: Este es solamente una ilustración de cómo la mayoría del trabajo implementaciones; además de depender de la implementación, esta técnica se descompone en presencia de herencia múltiple. Debe nunca hacer algo como esto en el código de producción; use RTTI en su lugar.

+2

¡¡¡¡¡¡¡¡¡¡¡¡¡¡Una muy buena !!! :). También +1 para RTTI. – Incognito

1

Puede acceder a vpointer e incluso puede llamar a cualquier método virtual en clase a través de vpointer. Pero recuerda que esto es MALVADO.

Ejemplo:

class A 
{ 
public: 
    void f1() 
    { 
     cout<<"bbb"<<endl;; 
    } 
    virtual void f2() 
    { 
     cout<<"ccc"<<endl;; 
    } 
    virtual void f3() 
    { 
     cout<<"ddd"<<endl;; 
    } 
}; 

y llamar principal

A a; 

typedef void (__thiscall* foo)(); 
(*(foo)((void**)(((void**)(&a))[0]))[1])(); 

Será acceder vpointer y luego pasará por el índice y ejecutará el segundo método en el vtable que es f3().

También tenga en cuenta el uso de RTTI como ya se ha sugerido.

+0

¡¡Guau !! Es brainbraking, pero genial! Nunca me gustaría tener tales preguntas en la entrevista. –

+0

¿Y cómo responde esto a la pregunta concreta? –

4

Sí, es muy posible de hacer: use dynamic_cast. Esta es una pregunta bastante mala, una ligeramente mejor podría ser "¿Cómo se implementa dynamic_cast?" pero realmente, si se me preguntara en una entrevista, tendría que preguntarme acerca del nous del entrevistador. Ser un buen, o incluso un gran programador de C++ no depende de saber minuciosamente detalles de implementación como este, pero estas son, por supuesto, preguntas fáciles para los evaluadores de segundo grado.

Cuestiones relacionadas