A questão é a seguinte: considere este pedaço 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;
}
Como posso usar os a
's aClass::test
como um argumento para function1
? Estou preso em fazer isso.
Eu gostaria de acessar um membro da classe.
c++
arguments
parameter-passing
function-pointers
pointer-to-member
Jorge Leitao
fonte
fonte
Respostas:
Não há nada de errado em usar ponteiros de função. No entanto, ponteiros para funções-membro não estáticas não são como ponteiros de funções normais: as funções-membro precisam ser chamadas em um objeto que é passado como um argumento implícito para a função. A assinatura da sua função de membro acima é, portanto,
em vez do tipo que você tenta usar
Uma abordagem poderia consistir em fazer o membro funcionar
static
em cujo caso ele não requer qualquer objeto a ser chamado e você pode usá-lo com o tipovoid (*)(int, int)
.Se você precisar acessar qualquer membro não estático da sua classe e precisar
void*
usar ponteiros de função, por exemplo, porque a função faz parte de uma interface C, sua melhor opção é sempre passar um para sua função, recebendo os ponteiros de função e chamando seu membro através de uma função de encaminhamento que obtém um objeto dovoid*
e depois chama a função de membro.Em uma interface C ++ adequada, você pode querer que sua função use argumentos modelados para que objetos de função usem tipos de classe arbitrários. Se o uso de uma interface de modelo é indesejável, você deve usar algo como
std::function<void(int, int)>
: você pode criar um objeto de função que possa ser chamado por eles, por exemplo, usandostd::bind()
.As abordagens de segurança de tipo usando um argumento de modelo para o tipo de classe ou um adequado
std::function<...>
são preferíveis a usar umvoid*
interface, pois elas removem o potencial de erros devido a uma conversão para o tipo errado.Para esclarecer como usar um ponteiro de função para chamar uma função de membro, aqui está um exemplo:
fonte
void*
, o que significa que você pode obter bugs muito desagradáveis, porque não é mais digitado.A resposta de @Pete Becker é boa, mas você também pode fazê-lo sem passar a
class
instância como um parâmetro explícitofunction1
no C ++ 11:fonte
void function1(std::function<void(int, int)>)
correto?void function1(std::function<void(int, int)> functionToCall)
e entãofunctionToCall(1,1);
. Tentei editar a resposta, mas alguém a rejeitou por não ter sentido por algum motivo. Vamos ver se é votado em algum momento.Um ponteiro para a função de membro é diferente de um ponteiro para a função. Para usar uma função de membro através de um ponteiro, você precisa de um ponteiro (obviamente) e de um objeto para aplicá-lo. Portanto, a versão apropriada
function1
seriae para chamá-lo:
fonte
function
navoid (aClass::*function)(int, int)
era um tipo, por causa disso é um tipo detypedef void (aClass::*function)(int, int)
.typedef int X;
define um tipo;int X;
cria um objeto.Desde 2011, se você pode alterar
function1
, faça o seguinte:( demonstração ao vivo )
Observe também que eu corrigi sua definição de objeto quebrado (
aClass a();
declara uma função).fonte
Eu fiz uma pergunta semelhante ( C ++ openframeworks passando vazio de outras classes ), mas a resposta que encontrei foi mais clara, então aqui a explicação para futuros registros:
é mais fácil usar std :: function como em:
e depois chame como:
ou ainda mais fácil:
onde você cria um lambda que chama o objeto capturando-o por referência
fonte
std::function
nodraw
entanto, em vez de copiá-lo em todas as chamadas.Eu fiz o membro funcionar como estático e todos os trabalhos:
fonte
Não sei por que essa solução incrivelmente simples foi descartada:
Resultado:
fonte
Se você realmente não precisa usar a instância
a
(ou seja, você pode torná-la estática como a resposta do @mathengineer ), basta passar uma lambda não capturada. (que deteriora para funcionar como ponteiro)Wandbox
nota: se
aClass
é caro construir ou tem efeito colateral, isso pode não ser um bom caminho.fonte
Você pode parar de bater com a cabeça agora. Aqui está o invólucro da função de membro para suportar funções existentes , recebendo funções C simples como argumentos.
thread_local
diretiva é a chave aqui.http://cpp.sh/9jhk3
Por favor, comente sobre quaisquer problemas com essa abordagem.
Outras respostas falham ao chamar funções simples existentes
C
: http://cpp.sh/8exunfonte
C
funções simples como argumentos.