Utilisation D'une fonction de membre de Classe C++ comme fonction de rappel C

j'ai une bibliothèque C qui a besoin d'une fonction de rappel d'être enregistré pour personnaliser le traitement. Le Type de fonction de rappel est int a(int *, int *) .

j'écris du code C++ similaire à ce qui suit et j'essaie d'enregistrer une fonction de Classe C++ comme fonction de rappel:

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() 
{

}

le compilateur lance l'erreur suivante:

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

mes questions:

  1. tout d'Abord, il possibilité d'enregistrer une fonction de mémoire de Classe C++ comme j'essaie de le faire et si oui comment? (J'ai lu de 32,8 à http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html . Mais à mon avis il ne résout pas le problème)
  2. y a-t-il une autre façon/meilleure de s'attaquer à ce problème?
39
demandé sur sharptooth 2009-06-16 14:24:07

5 réponses

vous pouvez faire cela si la fonction de membre est statique.

Non-fonctions membres statiques de la classe A ont implicite premier paramètre de type class A* qui correspond à ce pointeur. C'est pourquoi vous ne pouvez les enregistrer que si la signature du callback a aussi le premier paramètre de type class A* .

38
répondu sharptooth 2009-06-16 12:36:20

vous pouvez également le faire si la fonction membre n'est pas statique, mais qu'elle nécessite un peu plus de travail (Voir aussi convertir le pointeur de fonction C++ en pointeur de fonction c ):

#include <stdio.h>
#include <functional>

template <typename T>
struct Callback;

template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
   template <typename... Args> 
   static Ret callback(Args... args) {                    
      func(args...);  
   }
   static std::function<Ret(Params...)> func; 
};

template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::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<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2);
   callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);      
   register_with_library(func);      
}

int A::e(int *k, int *j) {
   return *k - *j;
}

A::~A() { }

int main() {
   A a;
}

cet exemple est complet dans le sens où il compile:

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

vous aurez besoin du drapeau c++11 . Dans le code, vous voyez que register_with_library(func) est appelé, où func est une fonction statique liée dynamiquement au membre la fonction e .

14
répondu Anne van Rossum 2017-05-23 12:10:23

le problème, c'est cette méthode != fonction. Le compilateur transformera votre méthode en quelque chose comme ça:

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

donc, c'est sûr que vous ne pouvez pas le passer, parce que l'instance de classe ne peut pas être passée en argument. Une façon de travailler autour est de faire la méthode comme statique, de cette façon il aurait le bon type. Mais il ne sera pas n'importe quelle instance de classe, et l'accès à des membres de classe non-statique.

L'autre solution est de déclarer une fonction statique Pointeur vers un Un initialisé la première fois. La fonction ne redirige l'appel que vers la classe:

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

alors vous pouvez enregistrer la fonction callback.

7
répondu Raoul Supercopter 2014-09-06 11:40:05

bien ...si vous êtes sur une plate-forme win32, il est toujours le méchant Médiateur ...

Médiateur dans Win32: la Simplification des rappels à la non-fonctions membres statiques

C'est une solution mais je ne recommande pas de l'utiliser.

Il a une bonne explication, et il est bon de savoir qu'il existe.

5
répondu TimW 2009-06-16 11:09:20

le problème avec l'utilisation d'une fonction membre est qu'elle a besoin d'un objet sur lequel agir - et C ne connaît pas les objets.

la façon la plus facile serait de faire ce qui suit:

//In a header file:
extern "C" int e(int * k, int * e);

//In your implementation: 
int e(int * k, int * e) { return 0; }
1
répondu PaulJWilliams 2009-06-16 10:29:06