La pregunta es la siguiente: considere este 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 los a
's aClass::test
como argumento para function1
? Estoy atrapado haciendo esto.
Me gustaría acceder a un miembro de la clase.
c++
arguments
parameter-passing
function-pointers
pointer-to-member
Jorge Leitao
fuente
fuente
Respuestas:
No hay nada de malo en usar punteros de función. Sin embargo, los punteros a funciones miembro no estáticas no son como los punteros de función normales: las funciones miembro deben llamarse en un objeto que se pasa como un argumento implícito a la función. La firma de su función miembro anterior es, por lo tanto
en lugar del tipo que intentas usar
Un enfoque podría consistir en hacer que el miembro funcione,
static
en cuyo caso no requiere invocar ningún objeto y puede usarlo con el tipovoid (*)(int, int)
.Si necesita acceder a cualquier miembro no estático de su clase y necesita seguir con punteros de función, por ejemplo, debido a que la función es parte de una interfaz C, su mejor opción es pasar siempre
void*
a su función tomando punteros de función y llamando su miembro a través de una función de reenvío que obtiene un objeto delvoid*
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 con plantilla para que los objetos de función usen tipos de clase arbitrarios. Si el uso de una interfaz con plantilla no es deseable, debe usar algo como
std::function<void(int, int)>
: puede crear un objeto de función invocable adecuadamente para estos, por ejemplo, usandostd::bind()
.Los enfoques de tipo seguro que utilizan un argumento de plantilla para el tipo de clase o un tipo adecuado
std::function<...>
son preferibles que el uso de unavoid*
interfaz, ya que eliminan la posibilidad de errores debido a una conversión al tipo incorrecto.Para aclarar cómo usar un puntero de función para llamar a una función miembro, aquí hay un ejemplo:
fuente
void*
, lo que significa que puede obtener errores muy desagradables, porque ya no está marcada como marcada.La respuesta de @Pete Becker está bien, pero también puede hacerlo sin pasar la
class
instancia como un parámetro explícitofunction1
en C ++ 11:fuente
void function1(std::function<void(int, int)>)
correcto?void function1(std::function<void(int, int)> functionToCall)
y luegofunctionToCall(1,1);
. Traté de editar la respuesta, pero alguien la rechazó por no tener ningún sentido por alguna razón. Veremos si se vota en algún momento.Un puntero a la función miembro es diferente de un puntero a la función. Para usar una función miembro a través de un puntero, necesita un puntero (obviamente) y un objeto para aplicarlo. Entonces la versión apropiada de
function1
seríay para llamarlo:
fuente
function
envoid (aClass::*function)(int, int)
era un tipo, debido a que es un tipo detypedef void (aClass::*function)(int, int)
.typedef int X;
define un tipo;int X;
crea un objetoDesde 2011, si puede cambiar
function1
, hágalo así:( demostración en vivo )
Observe también que arreglé su definición de objeto roto (
aClass a();
declara una función).fuente
Hice una pregunta similar ( openframeworks de C ++ pasando nulo desde otras clases ) pero la respuesta que encontré fue más clara, así que aquí la explicación para los registros futuros:
es más fácil usar std :: function como en:
y luego llame como:
o incluso más fácil:
donde crea una lambda que llama al objeto que lo captura por referencia
fuente
std::function
in endraw
lugar de copiarlo en cada llamada.Hice que el miembro funcionara como estático y todo funciona:
fuente
No estoy seguro de por qué se ha pasado por alto esta solución increíblemente simple:
Salida:
fuente
Si realmente no necesita usar la instancia
a
(es decir, puede hacerla estática como la respuesta de @mathengineer ), simplemente puede pasar una lambda sin captura. (que decae al puntero de función)Wandbox
nota: si
aClass
es costoso de construir o tiene efectos secundarios, esto puede no ser una buena manera.fuente
Puedes dejar de golpearte la cabeza ahora. Aquí está el contenedor de la función miembro para admitir funciones existentes que toman en funciones simples C como argumentos.
thread_local
directiva es la clave aquí.http://cpp.sh/9jhk3
Por favor comente sobre cualquier problema con este enfoque.
Otras respuestas no pueden llamar a las
C
funciones simples existentes : http://cpp.sh/8exunfuente
C
funciones simples como argumentos.