Dans MSVC, vous ne pouvez pas parcourir la vtable au moment de l'exécution et comparer l'égalité avec un pointeur de fonction membre donné, car ils ne sont pas identiques. L'un est le vrai pointeur, l'autre est un pointeur qui s'oriente vers le vrai. Cependant, avec ce compilateur, vous pouvez le faire à l'exécution avec un autre hack que j'ai découvert.
Créez une classe (nommée IndexFinder par exemple) dans laquelle vous déclarez autant de méthodes d'instance que les méthodes virtuelles max que vous pouvez avoir dans une classe. Chacune de ces méthodes doit retourner une valeur entière unique allant de 0 à votre maximum.
Créez une fausse table de méthode virtuelle et stockez vos pointeurs de méthode afin que l'entier qu'ils renvoient corresponde à l'index dans lequel vous les stockez (la méthode qui renvoie 0 sera la première dans votre vtable fictive). Lorsque vous souhaitez trouver l'index de n'importe quelle méthode virtuelle, vous devez effectuer une distribution incorrecte du pointeur de membre de méthode vers un pointeur de méthode IndexFinder.
Le principe est simple: pour les méthodes virtuelles, le compilateur générera du code qui s'origine vers la méthode réelle en utilisant vtable avec le bon index. Comme vous avez remplacé le compilateur généré vtable avec un faux, il va sauter à la vôtre et pas à la supposée. Comme votre méthode retourne l'index dans lequel elle est stockée, il vous suffit d'obtenir le retour et vous avez votre index.
Voici un code qui est plus explicite (je répète que c'est un bidouillage dépendant du compilateur, ceux qui n'aiment pas ça, ne le lisent pas ^^). Mais j'ai essayé, ça marche parfaitement car c'est juste un hack de redirection (je cherche un truc avec GCC, mais je ne l'ai pas encore trouvé).
Il est possible que cela dépende de la convention d'appel, je ne l'ai pas essayé dans tous les cas pour l'instant. Un avantage de cette astuce est que vous n'avez pas besoin de construire une instance de votre classe pour trouver l'index de l'une de ses méthodes virtuelles.
// In the header .h
class IndexFinder
{
typedef int (IndexFinder::*method_pointer)();
public:
template<typename _MethodPtr>
int getIndexOf(_MethodPtr ptr) {
return (reinterpret_cast<IndexFinder*>(&fake_vtable_ptr)->**((IndexFinder::method_pointer*)(&ptr)))()
}
protected:
int method0() { return 0; }
int method1() { return 1; }
int method2() { return 2; }
int method3() { return 3; }
protected:
typedef method_pointer fake_vtable_t [4];
static fake_vtable_t fake_vtable;
void* fake_vtable_ptr;
};
// In the cpp file
IndexFinder::fake_vtable_t IndexFinder::fake_vtable = {
&IndexFinder::method0 ,
&IndexFinder::method1 ,
&IndexFinder::method2 ,
&IndexFinder::method3
};
void* IndexFinder::fake_vtable_ptr = &IndexFinder::fake_vtable;
// to use it :
int index = IndexFinder::getIndexOf(&YourClass::yourVirtualMethod);
Passons à mon autre commentaire si vous l'avez lu, c'est exactement ce que je cherche! – Gbps