Использование функции члена classа C ++ в качестве функции обратного вызова C

У меня есть библиотека C, для которой требуется функция обратного вызова для настройки некоторой обработки. Тип функции обратного вызова – int a(int *, int *) .

Я пишу код на C ++, похожий на следующий, и попытаюсь зарегистрировать функцию classа C ++ в качестве функции обратного вызова:

 class A { public: A(); ~A(); int e(int *k, int *j); }; A::A() { register_with_library(e) } int A::e(int *k, int *e) { return 0; } A::~A() { } 

Компилятор выдает следующую ошибку:

 In constructor 'A::A()', error: argument of type 'int (A::)(int*, int*)' does not match 'int (*)(int*, int*)'. 

Мои вопросы:

  1. Прежде всего, можно зарегистрировать функцию membler classа C ++, как я пытаюсь сделать, и если да, то как? (Я читал 32.8 по адресу http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html . Но, по-моему, это не решает проблему)
  2. Есть ли альтернативный / лучший способ справиться с этим?

5 Solutions collect form web for “Использование функции члена classа C ++ в качестве функции обратного вызова C”

Вы можете сделать это, если функция-член статична.

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

Вы также можете сделать это, если функция-член не является статической, но для этого требуется немного больше работы (см. Также указатель функции Convert C ++ для указателя функции c ):

 #include  #include  template  struct Callback; template  struct Callback { template  static Ret callback(Args... args) { func(args...); } static std::function func; }; template  std::function Callback::func; void register_with_library(int (*func)(int *k, int *e)) { int x = 0, y = 1; int o = func(&x, &y); printf("Value: %i\n", o); } class A { public: A(); ~A(); int e(int *k, int *j); }; typedef int (*callback_t)(int*,int*); A::A() { Callback::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2); callback_t func = static_cast(Callback::callback); register_with_library(func); } int A::e(int *k, int *j) { return *k - *j; } A::~A() { } int main() { A a; } 

Этот пример завершен в том смысле, что он компилирует:

 g++ test.cpp -std=c++11 -o test 

Вам понадобится флаг c++11 . В коде вы видите, register_with_library(func) , где func – статическая функция, динамически связанная с функцией-членом e .

Проблема в том, что метод! = Function. Компилятор преобразует ваш метод в нечто подобное:

 int e( A *this, int *k, int *j ); 

Таким образом, он уверен, что вы не можете передать его, потому что экземпляр classа нельзя передать как аргумент. Один из способов обойти это сделать метод статичным, таким образом он будет иметь хороший тип. Но это не будет экземпляр classа и доступ к нестационарным членам classа.

Другой способ – объявить функцию со статическим указателем на A, инициализированным в первый раз. Функция перенаправляет вызов только classу:

 int callback( int *j, int *k ) { static A *obj = new A(); a->(j, k); } 

Затем вы можете зарегистрировать функцию обратного вызова.

Ну … если вы на платформе win32, всегда есть неприятный способ Thunking …

Thunking in Win32: упрощение обратных вызовов для нестатических функций-членов

Это решение, но я не рекомендую его использовать.
У него есть хорошее объяснение, и приятно знать, что он существует.

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

Самый простой способ – сделать следующее:

 //In a header file: extern "C" int e(int * k, int * e); //In your implementation: int e(int * k, int * e) { return 0; } 
  • Запись массива в диапазон Excel
  • Поверните простую C # DLL в компонент COM-взаимодействия
  • Маршал C ++ struct array в C #
  • Как использовать Microsoft.Office.Interop.Excel на компьютере без установленного MS Office?
  • Исключение из HRESULT: ошибка 0x800A03EC
  • Давайте будем гением компьютера.