2010-06-09 3 views
7

J'ai été récemment interviewé pour une position où C/C++ est la langue principale et pendant une question, on m'a dit qu'il est possible d'utiliser le vtable pour déterminer quelle classe dans une hiérarchie un pointeur de base est effectivement stocké.Comment utiliser le vtable pour déterminer le type de classe

Donc, si, par exemple, vous avez

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

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

et vous instancier A * pFoo = new B(), est-il en effet possible d'utiliser le vtable pour déterminer si pFoo contient un pointeur vers une instance de A ou B?

+0

Merci pour les réponses. J'ai oublié de mentionner que j'ai demandé si RTTI était ce qu'ils cherchaient, et ils ont dit qu'en général, ils désactivent RTTI alors ce n'est pas ça. Il est tout à fait possible que la solution qu'ils recherchaient soit ce que Martin B a décrit: –

Répondre

10

Cela dépend évidemment de l'implémentation mais, sur la plupart des implémentations, la représentation en mémoire d'un objet de classe A ou B commencera par un pointeur vers la vtable. Vous pouvez regarder ce pointeur vtable, le comparer aux pointeurs vtable pour les objets que vous savez être de classe A ou B, et déterminer la classe de l'objet de cette façon.

Pour illustrer (bien sûr, c'est tout sauf bon style):

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"); 

Important: est seulement une illustration de la façon dont la plupart des implémentations travail; En plus d'être dépendante de l'implémentation, cette technique se décompose en présence de plusieurs héritages. Vous devriez jamais faire quelque chose comme ceci dans le code de production; utilisez plutôt RTTI.

+2

Nice one !!! :) Aussi +1 pour RTTI. – Incognito

1

Vous pouvez accéder à vpointer et même vous pouvez appeler n'importe quelle méthode virtuelle en classe via vpointer. Mais rappelez-vous que c'est EVIL.

Exemple:

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

et appeler principal

A a; 

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

Il accédera vpointer et sera par index et exécutera la deuxième méthode vTable qui est f3().

Notez également d'utiliser RTTI comme déjà suggéré.

+0

Ouah !!!! C'est un brainbraking mais génial! Je ne voudrais jamais avoir de telles questions sur l'interview. –

+0

Et comment cela répond-il à la question concrète? –

4

Oui, c'est tout à fait possible - utilisez dynamic_cast. Ceci est une question assez moche - un peu mieux pourrait être "Comment dynamic_cast est-il implémenté?" mais vraiment, si on me le demandait lors d'une interview, je devrais m'interroger sur le bien-être de l'interviewer. Être un bon, ou même un bon programmeur C++ ne dépend pas de connaître les détails de mise en œuvre de nitpicking comme celui-ci, mais ce sont bien sûr des questions faciles à poser pour les évaluateurs secondaires.

Questions connexes