todas - Pasar una función miembro como argumento en C++
tipos de funciones en c (3)
Posible duplicado:
C ++, puntero a la función miembro
La pregunta es la siguiente: considere esta pieza de código:
#include <iostream>
class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};
void function1(void (*function)(int, int))
{
function(1, 1);
}
void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}
int main (int argc, const char* argv[])
{
aClass a();
function1(&test);
function1(&aClass::aTest); // <-- How should I point to a''s aClass::test function?
return 0;
}
¿Cómo puedo usar la aClass::test
como argumento para function1
? Estoy atrapado en hacer esto.
Me gustaría acceder a un miembro de la clase.
La respuesta de @Pete Becker está bien, pero también puede hacerlo sin pasar la instancia de class
como un parámetro explícito para function1
en C ++ 11:
#include <functional>
using namespace std::placeholders;
void function1(std::function<void(int, int)> fun)
{
fun(1, 1);
}
int main (int argc, const char * argv[])
{
...
aClass a;
auto fp = std::bind(&aClass::test, a, _1, _2);
function1(fp);
return 0;
}
No hay nada de malo con el uso de punteros a funciones. Sin embargo, los punteros a funciones de miembro no estáticas no son como punteros de función normal: las funciones de miembro deben invocarse sobre un objeto que se pasa como un argumento implícito a la función. La firma de su función de miembro arriba es, por lo tanto,
void (aClass::*)(int, int)
en lugar del tipo que intentas usar
void (*)(int, int)
Un enfoque podría consistir en hacer que la función miembro sea static
en cuyo caso no requiere que se llame a ningún objeto y puede usarlo con el tipo void (*)(int, int)
.
Si necesita acceder a cualquier miembro no estático de su clase y necesita seguir con los punteros de función, por ejemplo, porque la función es parte de una interfaz C, su mejor opción es pasar siempre un void*
a su función tomando punteros de función y llame a su miembro a través de una función de reenvío que obtiene un objeto del void*
y luego llama a la función miembro.
En una interfaz C ++ adecuada, es posible que desee ver cómo su función toma un argumento de plantilla para que los objetos de función usen tipos de clase arbitrarios. Si no se desea usar una interfaz con plantilla, debe usar algo como std::function<void(int, int)>
: puede crear un objeto de función invocable para esto, por ejemplo, usando std::bind()
.
Los enfoques de tipo seguro usando un argumento de plantilla para el tipo de clase o una std::function<...>
adecuada std::function<...>
son preferibles a usar una interfaz void*
ya que eliminan el potencial de errores debido a un lanzamiento al tipo incorrecto.
Para aclarar cómo usar un puntero de función para llamar a una función miembro, aquí hay un ejemplo:
// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}
void non_member(void*, int i0, int i1) {
std::cout << "I don''t need any context! i0=" << i0 << " i1=" << i1 << "/n";
}
struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "/n";
}
};
void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}
int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}
Un puntero a la función miembro es diferente de un puntero a función. Para usar una función de miembro a través de un puntero necesita un puntero (obviamente) y un objeto para aplicarlo. Entonces la versión apropiada de function1
sería
void function1(void (aClass::*function)(int, int), aClass& a) {
(a.*function)(1, 1);
}
y llamarlo:
aClass a; // note: no parentheses; with parentheses it''s a function declaration
function1(&aClass::test, a);