Pregunta

  

Duplicar posibles:
   Utilizando una función miembro de la clase C ++ como una función de devolución de llamada C

Estoy escribiendo una biblioteca orientada a objetos utilizando una biblioteca C (winpcap). Necesito pasar a la función de devolución de llamada que se llama cuando un paquete llega a la red como un puntero de función. Me gustaría pasar un puntero a la función miembro winpcap, para mantener mi objeto de diseño orientado y para permitir diferentes objetos para recibir diferentes paquetes. Sin embargo funciones miembro por lo que yo entiendo tienen una convención de llamada diferente, y por lo tanto no se puede pasar a una función C. ¿Hay una manera de solucionar este problema. Mis experimentos con boost :: bind (que casi no me las arreglo para usos distintos de ensayo y error) no son fructíferos.

¿Hay una manera de cambiar la convención de llamada de una función miembro?

Esta es la definición de la función de devolución de llamada que uso ahora y el paso real de la misma a winpcap

void pcapCallback( byte* param, const struct pcap_pkthdr* header, const byte* pkt_data );

pcap_loop( adhandle, 0, pcapCallback, NULL );

El pcap_loop sólo toma el nombre de la función (que está en el ámbito global en el momento). Esta es la definición del parámetro de puntero de función (tercero parámetro de pcap_loop ). Dado que este es el código de terceros que no puedo cambiar esto. Tendría que tener una función miembro que puede tomar esta forma:

typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);

Por lo que yo entiendo, la función miembro estará usando thiscall y el puntero de función c quiere un cdecl

¿Fue útil?

Solución

Por favor consulte el Tema detallada sobre

Cómo implementar una devolución de llamada a una función estática C ++ miembros?

Cómo implementar una devolución de llamada a una función de C ++ miembro no estática?

http://www.newty.de/fpt/callback.html

Otros consejos

Sólo se puede pasar a las funciones miembro static a una API C.

Si usted quiere tener una API C llamar a una función miembro, usted tiene que pasar dos piezas de datos: la función (miembro estático) y el objeto para el cual que se va a invocar.

Por lo general, las devoluciones de llamada de la API C tienen alguna forma de "datos de usuario", a menudo un void*, a través del cual se pueden crear un túnel de direcciones de su objeto:

// Beware, brain-compiled code ahead!

typedef void (*callback)(int data, void* user_data);

void f(callback cb, void* user_data);

class cpp_callback {
public:
  virtual ~cpp_callback() {} // sometimes needed
  void cb(int data) = 0;
  callback* get_callback() const {return &cb_;}
private
  static void cb_(int data, void* user_data)
  {
    cpp_callback* that = reinterpret_cast<my_cpp_callback*>(user_Data);
    that->cb(data);
  }
};

class my_callback {
public:
  void cb(int data) 
  {
     // deal with data
  }
};

void g()
{
  my_callback cb;
  f(cb.get_callback(), &cb);
}

Eso pcapCallback no se ve como si tiene datos de usuario, sin embargo, a menos que eso es lo que es param. Si ese es el caso, tendrá que almacenar la dirección del objeto de devolución de llamada de alguna variable global antes de llamar a la API. Algo como esto:

// Beware, brain-compiled code ahead!

typedef void (*callback)(int data);

void f(callback cb);

class cpp_callback {
public:
  cpp_callback() : the_old_cb_(this) {std::swap(the_cb_,the_old_cb_);}
  virtual ~cpp_callback()            {std::swap(the_cb_,the_old_cb_);}
  void cb(int data) = 0;
  callback* get_callback() const {return &cb_;}
private
  static cpp_callback* the_cb_;
  cpp_callback* the_old_cb_;
  static void cb_(int data, void* user_data) 
  {
    the_cb_->cb(data);
  }
};

class my_callback {
public:
  void cb(int data) { /* deal with data */ }
};

void g()
{
  my_callback cb;
  f(cb.get_callback(), &cb);
}

Como siempre con los datos globales, esto es peligroso si hay más de una instancia de la devolución de llamada está vivo. He tratado de minimizar el daño para que funcione si se anidan sus vidas. Cualquier otra cosa, sin embargo, le hará daño.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top