La question est la suivante: considérez ce morceau de code:
#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;
}
Comment puis-je utiliser les a
's aClass::test
comme argument pour function1
? Je suis coincé à faire ça.
Je souhaite accéder à un membre de la classe.
c++
arguments
parameter-passing
function-pointers
pointer-to-member
Jorge Leitao
la source
la source
Réponses:
Il n'y a rien de mal à utiliser des pointeurs de fonction. Cependant, les pointeurs vers des fonctions membres non statiques ne sont pas comme les pointeurs de fonction normaux: les fonctions membres doivent être appelées sur un objet qui est passé comme argument implicite à la fonction. La signature de votre fonction membre ci-dessus est donc
plutôt que le type que vous essayez d'utiliser
Une approche pourrait consister à faire fonctionner le membre,
static
auquel cas il ne nécessite aucun objet pour être appelé et vous pouvez l'utiliser avec le typevoid (*)(int, int)
.Si vous avez besoin d'accéder à un membre non statique de votre classe et que vous devez vous en tenir aux pointeurs de fonction, par exemple, parce que la fonction fait partie d'une interface C, votre meilleure option est de toujours passer un
void*
à votre fonction en prenant des pointeurs de fonction et d'appeler votre membre via une fonction de transfert qui obtient un objet de lavoid*
puis appelle la fonction membre.Dans une interface C ++ appropriée, vous voudrez peut-être jeter un œil à la manière dont votre fonction prend un argument basé sur un modèle pour que les objets fonction utilisent des types de classe arbitraires. Si l'utilisation d'une interface basée sur un modèle n'est pas souhaitable, vous devez utiliser quelque chose comme
std::function<void(int, int)>
: vous pouvez créer un objet fonction convenablement appelable pour ceux-ci, par exemple en utilisantstd::bind()
.Les approches de type sécurisé utilisant un argument de modèle pour le type de classe ou un type approprié
std::function<...>
sont préférables à l'utilisation d'unevoid*
interface car elles suppriment le potentiel d'erreurs dues à une conversion vers le type incorrect.Pour clarifier comment utiliser un pointeur de fonction pour appeler une fonction membre, voici un exemple:
la source
void*
, ce qui signifie que vous pouvez obtenir des bugs très méchants, car elle n'est plus vérifiée.La réponse de @Pete Becker est bonne, mais vous pouvez également le faire sans passer l'
class
instance en tant que paramètre explicitefunction1
dans C ++ 11:la source
void function1(std::function<void(int, int)>)
correct?void function1(std::function<void(int, int)> functionToCall)
et puisfunctionToCall(1,1);
. J'ai essayé de modifier la réponse mais quelqu'un l'a rejetée car elle n'avait aucun sens pour une raison quelconque. Nous verrons s'il obtient un vote positif à un moment donné.Un pointeur vers une fonction membre est différent d'un pointeur vers une fonction. Pour utiliser une fonction membre via un pointeur, vous avez besoin d'un pointeur vers elle (évidemment) et d'un objet auquel l'appliquer. La version appropriée de
function1
serait doncet pour l'appeler:
la source
function
envoid (aClass::*function)(int, int)
était un type, à cause de cela est un type danstypedef void (aClass::*function)(int, int)
.typedef int X;
définit un type;int X;
crée un objet.Depuis 2011, si vous pouvez changer
function1
, faites-le, comme ceci:( démo en direct )
Notez également que j'ai corrigé votre définition d'objet cassée (
aClass a();
déclare une fonction).la source
J'ai posé une question similaire ( openframeworks C ++ passant vide des autres classes ) mais la réponse que j'ai trouvée était plus claire, alors voici l'explication pour les enregistrements futurs:
il est plus facile d'utiliser std :: function comme dans:
puis appelez comme:
ou encore plus simple:
où vous créez un lambda qui appelle l'objet en le capturant par référence
la source
std::function
endraw
si au lieu de le copier sur chaque appel.J'ai fait fonctionner le membre comme statique et tout fonctionne:
la source
Je ne sais pas pourquoi cette solution incroyablement simple a été ignorée:
Production:
la source
Si vous n'avez pas vraiment besoin d'utiliser l'instance
a
(c'est-à-dire que vous pouvez la rendre statique comme la réponse de @mathengineer ), vous pouvez simplement passer un lambda sans capture. (qui désintègre le pointeur de fonction)Wandbox
Remarque: si la
aClass
construction est coûteuse ou a des effets secondaires, cela peut ne pas être un bon moyen.la source
Vous pouvez arrêter de vous cogner la tête maintenant. Voici le wrapper de la fonction membre pour prendre en charge les fonctions existantes prenant des fonctions C simples comme arguments.
thread_local
directive est la clé ici.http://cpp.sh/9jhk3
Veuillez commenter tout problème lié à cette approche.
Les autres réponses ne parviennent pas à appeler les
C
fonctions simples existantes : http://cpp.sh/8exunla source
C
fonctions simples comme arguments.