2012-04-02 2 views
5

Я подозреваю, что это невозможно, но я думал, что попрошу. Скажем, у меня есть класс с методом:Динамически создайте указатель на функцию, вызывающий метод на данном экземпляре

class A { 
public: 
    void b(int c); 
}; 

я могу сделать указатель на эту функцию члена:

void (A::*ptr)(int) = &A::b; 
(someAInstance.*ptr)(123); 

Я могу также злоупотребляют указатели на функции и сделать указатель, который принимает A аргумент непосредственно (Я не знаю, если это безопасно, но это работает на моей машине):

void (*ptr2)(A*, int) = (void (*)(A*, int))&A::b; 
(*ptr2)(&someAInstance, 123); 

то, что я хочу это как-то карри в A и создать указатель на функцию, который принимает только int, но вызывает метод A::b для определенного экземпляра A, который я предопредел. Экземпляр A будет оставаться постоянным для этого конкретного указателя функции, но может быть несколько указателей на функции, указывающих на один и тот же метод A::b, но с использованием разных экземпляров A. Например, я мог бы сделать отдельную функцию обертки:

A* someConstantA = new A; 
void wrapper(int c) { 
    someConstantA->b(c); 
} 

void (*ptr3)(int) = &wrapper; 

Теперь я могу использовать ptr3, не зная, какой именно A это диспетчерская вызова, но я должен был определить специальную функцию, чтобы справиться с этим. Мне нужен способ сделать указатели на любое количество экземпляров A, поэтому я не могу его жестко кодировать. Это возможно?


Редактировать: Должен ли я упомянул, я в ловушке в C++ 03 земли, а также не может использовать бустер

+0

Должно быть это указатель на функцию? То, что вы хотите сделать, часто выполняется с использованием функциональных объектов (например, с помощью 'std :: bind'). – kennytm

+0

@KennyTM Любое вызываемое произведение; Я не знаю 'std :: bind', теперь читаю –

+1

^^^ или' boost :: bind', если у вас нет C++ 11. – AJG85

ответ

1

Если у вас есть достаточно новый компилятор (например, GCC 4.2+), она должна включать в TR1, где вы могли бы использовать std::tr1::bind:

#include <cstdio> 
#include <tr1/functional> 

class A { 
public: 
    void b(int c) { 
     printf("%p, %d\n", (void*)this, c); 
    } 
}; 

int main() { 
    A* a = new A; 

    std::tr1::function<void(int)> f = 
     std::tr1::bind(&A::b, a, std::tr1::placeholders::_1); // <-- 
    f(4); 

    delete a; 

    return 0; 
} 

Он также выполним в чистом C++ 03 без TR1, но и гораздо более хаотичный:

std::binder1st<std::mem_fun1_t<void, A, int> > f = 
    std::bind1st(std::mem_fun(&A::b), a); 

Вы также можете написать свои собственные объекты функций.

Обратите внимание, что во всех вышеприведенных случаях вам нужно быть очень осторожными в отношении времени жизни a, поскольку это голый указатель. С std::tr1::bind вы могли бы по крайней мере обернуть указатель в std::tr1::shared_ptr, чтобы он мог жить так же долго, как объект функции.

std::tr1::shared_ptr<A> a (new A); 
std::tr1::function<void(int)> f = 
    std::tr1::bind(&A::b, a, std::tr1::placeholders::_1); 
0

Если вы используете C++ 11, вы можете использовать лямбда (непроверенный код):

template<typename T, typename A> 
std::function<void(A)> curry(T& object, void (T::*ptr)(A)) 
{ 
    return [](A a) { (object.*ptr)(std::forward<A>(a)); } 
} 
+0

Я бы убил за лямбду, но, к сожалению, нет; застрял с 03 –

3

Не создать функцию обертка , создать оболочку functor. Это позволяет вам инкапсулировать любое состояние, которое вы хотите (например, A*) в вызываемом объекте.

class A { 
public: 
    void b(int c) {} 
}; 

struct wrapper { 
    A* pA; 
    void (A::*pF)(int); 
    void operator()(int c) { (pA->*pF)(c); } 
    wrapper(A* pA, void(A::*pF)(int)) : pA(pA), pF(pF) {} 
}; 

int main() { 
    A a1; 
    A a2; 

    wrapper w1(&a1, &A::b); 
    wrapper w2(&a2, &A::b); 

    w1(3); 
    w2(7); 
} 
0

Я бы использовал Boost::bind для этого.

В основном:

class A 
{ 
    int myMethod(int x) 
    { 
     return x*x; 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    A test(); 
    auto callable = boost::bind(&A::myMethod, &A, _1); 

    // These two lines are equivalent: 
    cout << "object with 5 is: " << test.myMethod(5) << endl; 
    cout << "callable with 5 is: " << callable(5) << endl; 
    return 0; 
} 

Я думаю, что должно работать. Я также использую auto здесь, чтобы вывести тип, возвращаемый boost :: bind() во время компиляции, который ваш компилятор может поддерживать или не поддерживать. См. Это other question в stackoverflow для объяснения типа возврата bind.

Boost поддерживает обратно Visual Studio 2003 (я думаю), и все это будет работать там, хотя вы будете использовать BOOST_AUTO, я думаю. См. Другой вопрос, уже связанный для объяснения.

0

Что вы хотите сделать, это невозможно. Чтобы понять, почему, предположим, что это возможно - указатель функции должен указывать на функцию где-то в вашем исполняемом файле или на одну из ее библиотек, поэтому он должен указывать на функцию, которая знает, какой экземпляр A вызывать, также как и ваша функция-обертка , Поскольку экземпляр A неизвестен до выполнения, вам придется создавать эти функции во время выполнения, что невозможно.

То, что вы пытаетесь сделать, возможно в C++ 03, если вы счастливы передать объект функции, а не указатель на функцию.

Как другие уже дали решения с C++ 11 lambdas, TR1 и boost (все они красивее, чем показано ниже), но вы упомянули, что не можете использовать C++ 11, я вношу свой вклад в чистый C++ 03:

int main() 
{ 
    void (A::*ptr)(int) = &A::b; 
    A someAInstance; 

    std::binder1st<std::mem_fun1_t<void,A,int> > fnObj = 
     std::bind1st(std::mem_fun(ptr), &someAInstance); 
    fnObj(321); 
}; 
+0

Я думаю, что [ответ KennyTM] (http://stackoverflow.com/a/9983036/309308) уже охватывает ту же реализацию C++ 03, но спасибо за объяснение в начале –

+0

@MichaelMrozek Так оно и есть. он обновил его, так как я сначала прочитал существующие ответы – je4d

0

Я работал над чем-то с шаблоном класса делегата.

// T is class, R is type of return value, P is type of function parameter 
template <class T, class R, class P> class Delegate 
{ 
    typedef R (T::*DelegateFn)(P); 
private: 
    DelegateFn func; 
public: 
    Delegate(DelegateFn func) 
    { 
     this->func = func; 
    } 
    R Invoke(T * object, P v) 
    { 
     return ((object)->*(func))(v); 
    } 
}; 

class A { 
private: 
    int factor; 
public: 
    A(int f) { factor = f; } 
    int B(int v) { return v * factor; } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    A * a1 = new A(2); 
    A * a2 = new A(3); 

    Delegate<A, int, int> mydelegate(&A::B); 

    // Invoke a1->B 
    printf("Result: %d\n", mydelegate.Invoke(a1, 555)); 

    // Invoke a2->B 
    printf("Result: %d\n", mydelegate.Invoke(a2, 555)); 

    _getch(); 
    delete a1; 
    delete a2; 
    return 0; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^