Получить указатель на функцию-член объекта - PullRequest
26 голосов
/ 15 января 2012

Вот проблема:

1) У меня есть такой класс:

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

2) Внутри some_function я использую some_values из some_class объекта дляполучить результат.

3) Итак, у меня есть конкретный объект, и я хочу получить указатель на этот объект some_function.

Возможно ли это?Я не могу использовать some_fcn_ptr, потому что результат этой функции зависит от конкретного some_value объекта.

Как я могу получить указатель на some_function объекта?Спасибо.

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

Ответы [ 5 ]

28 голосов
/ 15 января 2012

Вы не можете, по крайней мере, это будет не только указатель на функцию.

Функция-член является общей для всех экземпляров этого класса. Все функции-члены имеют неявный (первый) параметр - this. Чтобы вызвать функцию-член для конкретного экземпляра, вам нужен указатель на эту функцию-член и этот экземпляр.

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;
}

Больше информации здесь C ++ FAQ

При использовании Boost это может выглядеть так (C ++ 11 предоставляет аналогичные функции):

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

C ++ 11 labdas:

#include <functional>

Some_class sc;
auto f = [&sc]() { sc.some_function(); };
f();
// or
auto f1 = [](Some_class& sc) { sc.some_function(); };
f1(sc);
11 голосов
/ 15 января 2012

Вы можете написать какой-нибудь Wrapper, который может использовать как функцию, так и метод в качестве параметра.

Я использовал следующие классы для запуска функций (это использовалось в одной моей программе 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);
}

И это расширение для "методов":

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

И затем использовать его как:

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

Я нашел макрос как это:

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

действительно полезно

9 голосов
/ 15 января 2012

Нет, вы не можете получить указатель на метод класса C ++ (если метод не объявлен как static).Причина в том, что метод класса всегда имеет указатель this, указатель на экземпляр класса.Но если бы вы вызывали метод через указатель, этот указатель не мог бы инкапсулировать указатель this, и тогда не было бы присоединенного экземпляра, и, следовательно, это поведение недопустимо.

5 голосов
/ 15 января 2012

Хотя это не совсем то, что вы просили, но если вы можете использовать C ++ 11, следующее, тем не менее, может удовлетворить ваши потребности (не проверено):

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); };
}
2 голосов
/ 04 марта 2017

Я использовал библиотеку Boost . Я включил "boost / bind.hpp" в мой код. Тогда метод с именем "fn" может быть определен как

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

...