2010-06-30 6 views
-2

Quelle est la meilleure façon d'appeler une fonction membre si vous avez un objet et un pointeur de fonction nue pointant vers le membre? Essentiellement je veux appeler le pointeur de fonction avec la convention d'appel thiscall. Arrière-plan: Je recherche dynamiquement des symboles dans une bibliothèque partagée, obtenant un pointeur de fonction d'usine et un pointeur vers une certaine fonction de membre que je veux appeler. La fonction membre elle-même n'est pas virtuelle. Je n'ai aucun contrôle sur la bibliothèque partagée, j'ai juste le binaire.Appel d'une fonction membre avec un pointeur de fonction nue

Exemple:

typedef void * (*GenericFptr)(); 
GenericFptr lookup(const char *); 

class CFoo; 

GenericFptr factoryfn(lookup("CFoo factory function")); 
CFoo *foo = reinterpret_cast<CFoo *>(factoryfn()); 

GenericFptr memberfn(lookup("CFoo member function")); 

// now invoke memberfn on foo 

Actuellement, je suis en utilisant un union pour convertir le pointeur de fonction à un pointeur vers une fonction membre. Il est laid et crée des dépendances au compilateur détails d'implémentation:

class CFoo { 
    public: 
    void *dummy() { return 0; } 
}; 
typedef void * (CFoo::*FooMemberPtr)(); 

union { 
    struct { 
    // compiler-specific layout for pointer-to-member 
    void *x, *y; 
    GenericFptr ptr; 
    } fnptr; 
    FooMemberPtr memberfn; 
} f; 

f.memberfn = &CFoo::dummy; // init pointer-to-member 
f.fnptr.ptr = memberfn; // rewrite pointer 

void *result = (foo->*f.memberfn)(); 
+0

comment avez-symboles pour la fin fonction membre dans l'objet partagé? lorsque j'essaie de le faire, les symboles de fonction de membre non virtuel ne sont pas publiés. –

Répondre

1

Malheureusement, un pointeur de fonction membre a plus d'informations qu'un pointeur de fonction standard, et quand vous obtenez le pointeur de fonction standard, la conversion à un pointeur de fonction membre serait effectivement essayer de générer des données supplémentaires à partir de rien.

Je ne pense pas qu'il y ait une façon portable de faire ce que vous essayez, bien que si le syndicat semble fonctionner, vous pourriez probablement vous en sortir. Encore une fois, vous aurez besoin de connaître la convention de représentation et d'appel de ces méthodes pour chaque compilateur que vous souhaitez utiliser pour construire le bode.

Si vous connaissez le nom de la fonction membre, pourquoi ne pouvez-vous pas simplement faire foo->dummy() par exemple? Sinon, la fonction de recherche doit fournir un pointeur de fonction membre complet ou la bibliothèque doit fournir une interface C wrapper avec des fonctions normales auxquelles un pointeur this peut être transmis.

+0

Merci. Appel de la fonction directement n'est pas une option car je ne peux pas lier à la bibliothèque au moment de la compilation. La fonction de recherche est également fournie par le système d'exploitation sous-jacent et ne peut pas être facilement remplacée. – laalto

+0

Je pense que vous pourriez vous tromper, Mark. Lallato a 2 pointeurs. Étant donné un pointeur vers une instance et une adresse de fonction membre, il est tout à fait possible d'appeler une fonction membre sur une instance. Il est clairement non trivial pour la fonction virtuelle et les fonctions possibles même non virtuelles définies dans une classe qui a des fonctions virtuelles. La fonction non-virtuelle sur une classe ordinaire devrait être facile, cependant l'application portative exige toujours la connaissance ou le type dans quelques compilateurs. Je vais cuire un exemple dans GCC qui est le plus facile. –

2

Un pointeur vers une fonction membre ne peut pas être stocké dans un pointeur de fonction, car il a besoin de plus d'informations (par exemple en cas d'héritage multiple un décalage peut avoir à être appliqué à cela avant l'appel). Vous ne pouvez donc pas vous passer de la connaissance des détails d'implémentation.

Si vous voulez être portable, le plus simple est que votre bibliothèque fournisse des fonctions wrapper pour l'appel des membres.

+0

Merci. Je connais suffisamment de détails de mise en œuvre pour que le truc syndical fonctionne mais je n'aimerais pas le faire. Je ne peux pas toucher la bibliothèque elle-même car elle est déjà déployée sur des centaines de millions d'instances. – laalto

+1

L'ajout d'une seconde bibliothèque fournissant l'encapsuleur serait-il acceptable? Le problème que vous formulez n'a pas de solution standard, vous devez donc changer d'approche. Sans connaître tout le contexte, il est assez difficile de proposer des choses. – AProgrammer

Questions connexes