c ++ хранит указатель на функцию-член неизвестного класса - PullRequest
5 голосов
/ 16 октября 2011

Я хочу сохранить указатель на объект и указатель на его метод известной подписи. Если я знаю класс, то этот указатель имеет тип:

int (MyClass::*pt2Member)(float, char, char)

Но как мне сохранить указатель, если я не знаю тип?

Я хочу сделать что-то вроде этого:

myObject.callThisFuncLater(&otherObject, &otherObject::method)

Как сохранить указатель на метод method в myObject и вызвать его позже?

Ответы [ 4 ]

5 голосов
/ 16 октября 2011

Самый простой способ сделать это, если у вас есть доступ к расширениям библиотеки TR1 STL (доступным в gcc и Visual Studio 2008 и далее). Std :: function и std :: bind могут использоваться для переноса вызова, который может бытьвызывается позже. Эта функция также доступна в функции boost и boost bind:

#include <functional>

class MyClass {
public:
  template<typename T> callThisFuncLater(T& otherObject,
                                         int(T::*)(float, char, char) method) {
    return storedInvocation_ = std::bind(otherObject, 
                                  method, 
                                  std::placeholders::_1,   // float
                                  std::placeholders::_2,   // char
                                  std::placeholders::_3);  // char
  }

  int callStoredInvocation(float a, char b, char c) {
    storedInvocation_(a, b, c);
  }

private:
  std::function<int(float, char, char)> storedInvocation_;
};
3 голосов
/ 16 октября 2011

Не существует простого способа сделать это так, как он изначально встроен в язык или стандартную библиотеку (хотя он был недавно добавлен). Если вы знакомы с Boost, они включают решение для этого - Boost.Function .

Если по какой-либо причине вы не можете или не хотите использовать Boost, существует общий способ сделать это с помощью шаблонов (что, по общему признанию, довольно похоже на решение Boost):

class FncPtr
{
public:
    virtual int call(float, char, char) = 0;
};

template <typename T>
class ClassFncPtr : public FncPtr
{
     int (T::*pt2Member)(float, char, char);
     T *inst;
public:
     ClassFncPtr(T* who, int (T::*memfunc)(float,char,char))
         : inst(who), pt2Member(memfunc)
     {
     }
     int call(float a, char b, char c)
     {
         return (inst->*pt2Member)(a,b,c);
     }
};

template <typename T>
FncPtr * makeFuncPointer(T* who, int (T::*memfunc)(float,char,char))
{
    return new ClassFncPtr<T>(who,memfunc);
}

Вы также можете создать подкласс FncPtr, чтобы иметь возможность использовать функции, не относящиеся к классу, если хотите.

2 голосов
/ 16 октября 2011

Вы можете использовать boost::functionboost::bind) для хранения фрагмента кода, который будет вызван позже.

class MyClass
{
public:
    void callThisFuncLater( boost::function< int (float, char, char) > callBack );
};
...
myObject.callThisFuncLater( boost::bind( &otherObject::method, &otherObject ) );
0 голосов
/ 16 октября 2011

Лично я бы выбрал другой дизайн. Просто потому, что с указателями на функции-члены в C ++ работать нелегко. Лично я бы предпочел использовать интерфейсы и наследовать от них и анализировать их.

Одна из проблем с указателями на функции-члены заключается в том, что они реализованы по-разному в разных компиляторах. Если вы используете компиляторы Borland / Embarcardero и хотите ограничиться этим, вы можете использовать ключевое слово __closure, однако, скорее всего, это не так, и поэтому вам придется использовать какой-то другой специфичный для компилятора реализации, или используйте один из вспомогательных классов повышения, например, функцию.

Но если вы оказались в ситуации, когда вам полезно использовать указатели на функции-члены в C ++, пересмотрите свой дизайн.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...