web-dev-qa-db-fra.com

Obtenir un pointeur sur la fonction membre de l'objet

Voici le problème:

1) J'ai une classe comme ça:

class some_class
{
public:
    some_type some_value;
    int some_function(double *a, double *b, int c, int d, void *e);
};

2) À l'intérieur some_function, J'utilise some_values de some_class objet pour obtenir un résultat.

3) Donc, j'ai un objet concret et je veux obtenir un pointeur sur cet objet some_function.

C'est possible? Je ne peux pas utiliser some_fcn_ptr car le résultat de cette fonction dépend du béton some_value d'un objet.

Comment puis-je obtenir un pointeur sur some_function d'un objet? Merci.

typedef  int (Some_class::*some_fcn_ptr)(double*, double*, int, int, void*);
28
Alex Hoppus

Vous ne pouvez pas, au moins ce ne sera pas seulement un pointeur vers une fonction.

La fonction membre est commune à toutes les instances de cette classe. Toutes les fonctions membres ont un paramètre implicite (premier) - this. Pour appeler une fonction membre pour une instance spécifique, vous devez pointer vers cette fonction membre et cette instance.

class Some_class
{
public:
    void some_function() {}
};

int main()
{
    typedef void (Some_class::*Some_fnc_ptr)();
    Some_fnc_ptr fnc_ptr = &Some_class::some_function;

    Some_class sc;

    (sc.*fnc_ptr)();

    return 0;
}

Plus d'informations ici dans FAQ C++

En utilisant Boost , cela peut ressembler (C++ 11 fournit des fonctionnalités similaires):

#include <boost/bind.hpp>
#include <boost/function.hpp>

boost::function<void(Some_class*)> fnc_ptr = boost::bind(&Some_class::some_function, _1);
Some_class sc;
fnc_ptr(&sc);

Labdas de C++ 11:

#include <functional>

Some_class sc;
auto f = [&sc]() { sc.some_function(); };
f();
// or
auto f1 = [](Some_class& sc) { sc.some_function(); };
f1(sc);
30
Andriy Tylychko

Vous pouvez écrire une sorte de Wrapper capable d'utiliser à la fois la fonction ou la méthode comme paramètre.

J'ai utilisé les classes suivantes pour lancer des fonctions (il a été utilisé dans un de mes programmes SDL):

class CallbackFunction {
public:
    // Constructor, copy constructor and destructor

    virtual int execute( SDL_keysym* keysym) const;
    virtual int operator()( SDL_keysym* keysym) const;

protected:
    int( *callback)( SDL_keysym*));
}

int CallbackFunction::execute( SDL_keysym* keysym) const{
    return callback(keysym);
}

int CallbackFunction::operator()( SDL_keysym* keysym) const{
    return callback( keysym);
}

Et cette extension pour "méthodes":

template<class T>
class CallbackMethod : public CallbackFunction {
public:
    // Constructor, copy constructor and destructor
    CallbackMethod( T *object, int(T::*callback)( SDL_keysym* keysym));

    int execute( SDL_keysym* keysym) const;
    int operator()(SDL_keysym* keysym) const;

protected:
    T *object;
    int(T::*method)( SDL_keysym* keysym);
};

// Object initialization (constructor)
template<class T>
CallbackMethod<T>::CallbackMethod( T *object, int(T::*callback)( SDL_keysym* keysym)):
    CallbackFunction( NULL),object(object),method(callback){
}


// Responsible for executing
template<class T>
int CallbackMethod<T>::execute( SDL_keysym* keysym) const {
    return (object->*method)(keysym);
}
template<class T>
int CallbackMethod<T>::operator()( keysym) const {
    return (object->*method)( keysym);
}

Et puis utilisez-le comme:

CallbackFunction *callback;
callback = new CallbackFunction( myFunction);
callback = new CallbackMethod<A>( instanceOfA, instanceOfA::myMethod);
callback = new CallbackMethod<B>( instanceOfB, instanceOfB::myMethod);
...
callback( keysym);

J'ai trouvé la macro comme ceci:

CALLBACK(object,method) new CallbackMethod<typeof(*object)>( object, &method)

vraiment utile

11
Vyktor

Non, vous ne pouvez pas obtenir de pointeur sur une méthode de classe C++ (sauf si la méthode est déclarée statique). La raison en est qu'une méthode de classe a toujours le pointeur this, un pointeur sur l'instance de classe. Mais si vous appeliez la méthode via un pointeur, ce pointeur ne pourrait pas encapsuler le pointeur this, puis il n'y aurait aucune instance attachée, et donc ce comportement n'est pas légal.

9
Dov Grobgeld

Bien que ce ne soit pas exactement ce que vous avez demandé, si vous pouvez utiliser C++ 11, les éléments suivants pourraient néanmoins répondre à vos besoins (non testés):

std::function<int(double*, double*, int, int, void*)>
  some_function_of(Some_class& obj)
{
  return [&](double* a, double* b, int c, int d, void* e){
    return obj.some_func(a, b, c, d, e); };
}
5
celtschk

J'ai utilisé la bibliothèque Boost . J'ai inclus "boost/bind.hpp" dans mon code. Ensuite, une méthode nommée "fn" peut être définie comme

auto fn = boost :: bind (ClassName :: methodName, classInstanceName, boost :: placeholders :: _ 1);

2
Zoob