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::testcomo 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,
staticen 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
classinstancia como un parámetro explícitofunction1en 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
function1seríay para llamarlo:
fuente
functionenvoid (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::functionin endrawlugar 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
aClasses 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_localdirectiva es la clave aquí.http://cpp.sh/9jhk3
Por favor comente sobre cualquier problema con este enfoque.
Otras respuestas no pueden llamar a las
Cfunciones simples existentes : http://cpp.sh/8exunfuente
Cfunciones simples como argumentos.