2010-11-18 5 views
3

Actuellement, j'ai une classe de ce genre, raccourci pour la simplicité:Cast à fonction membre pointeur normal

class MyClass { 
    public: 
     MyClass(); 
     void* someFunc(void* param); 
} 

Maintenant je dois appeler une fonction de ce genre (non membre d'une classe et que je malheureusement ne peut pas changer) mais que je dois appeler de toute façon:

void secondFunc(int a, int b, void *(*pCallback)(void*)); 

maintenant je dois passer l'adresse de someFunc d'une instance.

Un échantillon ne fonctionne pas:

MyClass demoInstance; 
// some other calls 
secondFunc(1, 2, demoInstance::someFunc()); 

J'ai essayé aussi avec des moulages comme:

(void* (*)(void*)) demoInstance::someFunc; 
reinterpret_cast<(void* (*)(void*))>(demoInstance::someFunc); 

Comment puis-je appeler cette fonction avec une classe fonction de membre en tant que paramètre de sorte que celui-ci peut l'utiliser comme rappel?

Toute idée ou remarque est appréciée. Merci et salutations tobias

+1

Vous * devez * fournir une instance; c'est un comportement indéfini sinon. Qu'est-ce que vous essayez d'accomplir. – strager

+0

Quel pointeur est passé dans la fonction de rappel en tant que paramètre? Si vous pouvez le spécifier d'une manière ou d'une autre, vous devriez être capable de créer un 'struct Foo {MyClass * a; void * b; }; ', puis utilisez' void * MyCallback (void * foo_) {Foo * foo = static_cast (foo_); retourne foo-> a-> someFunc (foo-> b); } 'comme rappel. –

Répondre

5

La différence entre une fonction C et une fonction membre C++ est que la fonction C utilise cdecl convention d'appel, tandis que les fonctions de membre utilise thiscall convention d'appel (et vous ne pouvez pas même prendre leur adresse!). Si je comprends bien, vous voulez que secondFunc() appelle la fonction membre d'une instance particulière de la classe (appelons-le this).Eh bien, les adresses des fonctions membres de toutes les instances d'une classe particulière sont les mêmes. Pour passer le pointeur à l'objet, vous aurez besoin d'un canal latéral. Dans ce cas, il pourrait s'agir d'une variable statique. Ou, si vous voulez le support MT, vous devrez utiliser le stockage local de thread (TLS),

Cela nécessite un callback par membre de type SomeFunc, mais vous auriez besoin d'un répartiteur quelque part de toute façon.

+0

Comment le static 'SomeFunc_callback_wrapper' accède-t-il à l'instance' obj'? – strager

+0

l'a fait de cette façon. Merci! – Atmocreations

8

Vous ne pouvez pas appeler la fonction membre directement. Les pointeurs de fonction membre ne sont pas du même type que les pointeurs de fonction.

Vous devrez envelopper d'une manière ou d'une autre une fonction compatible. Cependant, si votre fonction externe (celle qui prend le pointeur de fonction comme argument) n'est pas re-entrant et ne fournit pas un argument supplémentaire à utiliser par le pointeur de fonction, vous ne serez pas en mesure de passer l'instance sur laquelle le membre fonction fonctionne, de sorte que vous ne serez pas en mesure de faire l'appel.

+0

Eh bien, la fonction externe fait partie d'une bibliothèque et la seule façon de voir est d'avoir un tableau statique de ces pointeurs de fonction ... toutes les fonctions définies par moi-même et appelées, appelant simplement la fonction callback de l'objet correspondant. Est-ce vraiment impossible? – Atmocreations

+0

@Atmocreations: oui, c'est vraiment impossible. Dans le but de voir pourquoi, notez que aussi bien que le paramètre 'void *', 'someFunc' a également besoin d'une valeur de' this'. C'est comme s'il avait deux paramètres, dont l'un ne peut être fourni qu'en faisant un appel de fonction membre. 'secondFunc' ne fait pas d'appel de fonction membre, comment le code est-il censé déterminer' this'? –

+0

okay à droite. J'ai le problème. merci – Atmocreations

0
class MyClass 
{ 
public: 
    MyClass(); 
    void* someFunc(void* param); 
}; 

void* callback(void*) 
{ 
    MyClass instance; 
    instance.someFunc(0 /* or whatever */); 
} 

void foo() 
{ 
    secondFunc(1, 2, callback); 
} 
0

N'a pas vu la partie de ne pas être en mesure de changer la deuxième fonction avant.

Définir une structure avec des pointeurs à la fonction de membre et à l'objet:

struct MyData { 
    MyStruct *myInstance; 
    (void *)(MyStruct::myFunction)(void *data); 
    void * dataPointer ; 
} 

créer une fonction qui peut appeler la méthode appropriée:

void *proxyFunc(MyData *data) 
{ 
    return (data->myInstance->*(data->myFunction))(data->dataPointer); 
} 

appeler ensuite la fonction 2 comme:

MyData dataP = { someInstance, &MyStruct::someFunc, &dataPtr }; 
secondFunc(proxyFunc, &dataP); 
1

Il existe un moyen de contourner ce problème. Puisque les noms C++ sont modifiés, vous ne pouvez pas l'utiliser directement pour des fonctions non statiques. Cependant, comme les fonctions non statiques ont les mêmes signatures que les fonctions C, vous pouvez les utiliser directement comme callbacks. Donc, pour les fonctions non statiques, vous pouvez avoir des wrappers de fonctions statiques. This page explique cette approche en détail.

+0

merci d'abord. semble intelligent, va vérifier les détails plus tard. – Atmocreations

0

Voir cet exemple:

#include <iostream> 

class MyClass 
{ 
public: 
    MyClass() 
    { 
    } 

    void* someFunc(void* param) 
    { 
     std::cout << "someFunc" << std::endl; 
     return (void*)0; 
    } 
}; 

typedef void* (MyClass::*MemFun)(void*); 

void secondFunc(int a, int b, MemFun fn) 
{ 
    MyClass* ptr = 0; 
    // This is dangerous! If the function someFunc do not operate the data in the class. 
    // You can do this. 
    (ptr->*fn)(0); 
    std::cout << "Call me successfully!" << std::endl; 
} 

int main() 
{ 
    secondFunc(1, 2, &MyClass::someFunc); 

    system("pause"); 

    return 0; 
} 
Questions connexes