J'ai du mal à voir l'utilité des pointeurs de fonction. Je suppose que cela peut être utile dans certains cas (ils existent, après tout), mais je ne peux pas penser à un cas où il est préférable ou inévitable d'utiliser un pointeur de fonction.
Pourriez-vous donner un exemple de bonne utilisation des pointeurs de fonction (en C ou C ++)?
Réponses:
La plupart des exemples se résument à des rappels : vous appelez une fonction en
f()
passant l'adresse d'une autre fonctiong()
etf()
appelezg()
une tâche spécifique. Si vous passezf()
l'adresse de à lah()
place, vousf()
rappellerez à lah()
place.En gros, c'est un moyen de paramétrer une fonction: une partie de son comportement n'est pas codée en dur dans
f()
, mais dans la fonction de rappel. Les appelants peuvent fairef()
se comporter différemment en passant différentes fonctions de rappel. Un classique provientqsort()
de la bibliothèque standard C qui prend son critère de tri comme un pointeur vers une fonction de comparaison.En C ++, cela se fait souvent à l'aide d' objets fonction (également appelés foncteurs). Ce sont des objets qui surchargent l'opérateur d'appel de fonction, vous pouvez donc les appeler comme s'il s'agissait d'une fonction. Exemple:
L'idée derrière cela est que, contrairement à un pointeur de fonction, un objet fonction peut transporter non seulement un algorithme, mais également des données:
Un autre avantage est qu'il est parfois plus facile d'appeler en ligne des objets de fonction que d'appeler via des pointeurs de fonction. C'est une raison pour laquelle le tri en C ++ est parfois plus rapide que le tri en C.
la source
Eh bien, je les utilise généralement (professionnellement) dans les tables de saut (voir aussi cette question StackOverflow ).
Les tables de sauts sont couramment (mais pas exclusivement) utilisées dans les machines à états finis pour les rendre pilotées par les données. Au lieu d'un commutateur / boîtier imbriqué
vous pouvez créer un tableau 2D de pointeurs de fonction et appeler simplement
handleEvent[state][event]
la source
Exemples:
la source
std::sort
lecomp
paramètre de comme une stratégieL'exemple "classique" de l'utilité des pointeurs de fonction est la
qsort()
fonction de bibliothèque C , qui implémente un tri rapide. Afin d'être universel pour toutes les structures de données que l'utilisateur peut créer, il faut quelques pointeurs vides vers des données triables et un pointeur vers une fonction qui sait comment comparer deux éléments de ces structures de données. Cela nous permet de créer notre fonction de choix pour le travail, et en fait permet même de choisir la fonction de comparaison au moment de l'exécution, par exemple pour le tri croissant ou décroissant.la source
D'accord avec tout ce qui précède, plus .... Lorsque vous chargez une dll dynamiquement au moment de l'exécution, vous aurez besoin de pointeurs de fonction pour appeler les fonctions.
la source
Je vais aller à contre-courant ici.
En C, les pointeurs de fonction sont le seul moyen d'implémenter la personnalisation, car il n'y a pas d'OO.
En C ++, vous pouvez utiliser des pointeurs de fonction ou des foncteurs (objets de fonction) pour le même résultat.
Les foncteurs présentent un certain nombre d'avantages par rapport aux pointeurs de fonction bruts, en raison de leur nature d'objet, notamment:
operator()
lambda
etbind
)Personnellement, je préfère les foncteurs aux pointeurs de fonction (malgré le code standard), principalement parce que la syntaxe des pointeurs de fonction peut facilement devenir poilue (à partir du didacticiel du pointeur de fonction ):
La seule fois où j'ai vu des pointeurs de fonction utilisés là où les foncteurs ne pouvaient pas, c'était dans Boost.Spirit. Ils ont complètement abusé de la syntaxe pour passer un nombre arbitraire de paramètres en tant que paramètre de modèle unique.
Mais comme les modèles variadiques et les lambdas sont au coin de la rue, je ne suis pas sûr que nous utiliserons des pointeurs de fonction dans du code C ++ pur pour longtemps maintenant.
la source
bind
oufunction
utilisez des pointeurs de fonction. C'est comme dire que nous n'utilisons pas de pointeurs en C ++ parce que nous utilisons des pointeurs intelligents. Quoi qu'il en soit, je suis pinailleur.En C, l'utilisation classique est la fonction qsort , où le quatrième paramètre est un pointeur vers une fonction à utiliser pour effectuer le tri dans le tri. En C ++, on aurait tendance à utiliser des foncteurs (objets qui ressemblent à des fonctions) pour ce genre de chose.
la source
J'ai récemment utilisé des pointeurs de fonction pour créer une couche d'abstraction.
J'ai un programme écrit en C pur qui fonctionne sur des systèmes embarqués. Il prend en charge plusieurs variantes matérielles. Selon le matériel sur lequel j'exécute, il doit appeler différentes versions de certaines fonctions.
Au moment de l'initialisation, le programme détermine sur quel matériel il s'exécute et remplit les pointeurs de fonction. Toutes les routines de niveau supérieur du programme appellent simplement les fonctions référencées par des pointeurs. Je peux ajouter la prise en charge de nouvelles variantes matérielles sans toucher aux routines de niveau supérieur.
J'avais l'habitude d'utiliser des instructions switch / case pour sélectionner les versions de fonction appropriées, mais cela est devenu peu pratique car le programme a grandi pour prendre en charge de plus en plus de variantes matérielles. J'ai dû ajouter des déclarations de cas partout.
J'ai également essayé des couches de fonctions intermédiaires pour déterminer la fonction à utiliser, mais elles n'ont pas beaucoup aidé. Je devais toujours mettre à jour les déclarations de cas à plusieurs endroits chaque fois que nous ajoutions une nouvelle variante. Avec les pointeurs de fonction, je n'ai qu'à changer la fonction d'initialisation.
la source
Comme riche dit ci-dessus, il est très courant pour les pointeurs de fonctions dans Windows de référencer une adresse qui stocke la fonction.
Lorsque vous programmez
C language
sur une plate-forme Windows, vous chargez essentiellement un fichier DLL dans la mémoire principale (en utilisantLoadLibrary
) et pour utiliser les fonctions stockées dans la DLL, vous devez créer des pointeurs de fonctions et pointer vers ces adresses (en utilisantGetProcAddress
).Références:
LoadLibrary
GetProcAddress
la source
Les pointeurs de fonction peuvent être utilisés en C pour créer une interface avec laquelle programmer. En fonction de la fonctionnalité spécifique requise au moment de l'exécution, une implémentation différente peut être affectée au pointeur de fonction.
la source
Ma principale utilisation d'entre eux a été les RAPPELS: lorsque vous avez besoin de sauvegarder des informations sur une fonction à appeler plus tard .
Disons que tu écris Bomberman. 5 secondes après que la personne ait largué la bombe, celle-ci devrait exploser (appelez la
explode()
fonction).Maintenant, il y a 2 façons de le faire. Une façon est de «sonder» toutes les bombes sur l'écran pour voir si elles sont prêtes à exploser dans la boucle principale.
Une autre façon consiste à joindre un rappel à votre système d'horloge. Lorsqu'une bombe est posée, vous ajoutez un rappel pour l'appeler bomb.explode () lorsque le moment est venu .
Ici
callback.function()
peut être n'importe quelle fonction , car c'est un pointeur de fonction.la source
Utilisation du pointeur de fonction
Pour appeler la fonction dynamiquement en fonction de l'entrée de l'utilisateur. En créant une carte de chaîne et de pointeur de fonction dans ce cas.
De cette façon, nous avons utilisé le pointeur de fonction dans notre société actuelle. Vous pouvez écrire un nombre 'n' de fonction et les appeler en utilisant cette méthode.
PRODUCTION:
la source
Une perspective différente, en plus d'autres bonnes réponses ici:
En C, vous n'utilisez des pointeurs de fonction, et non des fonctions (directement).
Je veux dire, vous écrivez des fonctions, mais vous ne pouvez pas manipuler les fonctions. Il n'y a pas de représentation à l'exécution d'une fonction en tant que telle que vous pouvez utiliser. Vous ne pouvez même pas appeler "une fonction". Lorsque vous écrivez:
ce que vous dites en fait, c'est "effectuer un appel au
my_function
pointeur avec l'argument spécifié". Vous passez un appel via un pointeur de fonction. Cette décomposition en pointeur de fonction signifie que les commandes suivantes sont équivalentes à l'appel de fonction précédent:et ainsi de suite (merci @LuuVinhPhuc).
Donc, vous utilisez déjà des pointeurs de fonction comme valeurs . Évidemment, vous voudriez avoir des variables pour ces valeurs - et c'est là que toutes les utilisations d'autres métions entrent en jeu: Polymorphisme / personnalisation (comme dans qsort), rappels, tables de saut, etc.
En C ++, les choses sont un peu plus compliquées, puisque nous avons des lambdas et des objets avec
operator()
, et même unestd::function
classe, mais le principe est toujours le même.la source
(&my_function)(my_arg)
,(*my_function)(my_arg)
,(**my_function)(my_arg)
,(&**my_function)(my_arg)
,(***my_function)(my_arg)
... parce que les fonctions se désintègrent à des pointeurs de fonctionPour les langages OO, pour effectuer des appels polymorphes dans les coulisses (cela est également valable pour C jusqu'à un certain point je suppose).
De plus, ils sont très utiles pour injecter un comportement différent à une autre fonction (toto) au moment de l'exécution. Cela fait de la fonction foo une fonction d'ordre supérieur. En plus de sa flexibilité, cela rend le code foo plus lisible car il vous permet d'en extraire cette logique supplémentaire de "if-else".
Il permet de nombreuses autres choses utiles en Python comme les générateurs, les fermetures, etc.
la source
J'utilise beaucoup de pointeurs de fonction pour émuler des microprocesseurs qui ont des opcodes de 1 octet. Un tableau de 256 pointeurs de fonction est la manière naturelle de l'implémenter.
la source
Une utilisation du pointeur de fonction pourrait être là où nous ne souhaitons pas modifier le code où la fonction est appelée (ce qui signifie que l'appel peut être conditionnel et que dans des conditions différentes, nous devons effectuer différents types de traitement). Ici, les pointeurs de fonction sont très pratiques, car nous n'avons pas besoin de modifier le code à l'endroit où la fonction est appelée. Nous appelons simplement la fonction en utilisant le pointeur de fonction avec les arguments appropriés. Le pointeur de fonction peut être amené à pointer vers différentes fonctions de manière conditionnelle. (Cela peut être fait quelque part pendant la phase d'initialisation). De plus, le modèle ci-dessus est très utile, si nous ne sommes pas en mesure de modifier le code là où il est appelé (supposons que ce soit une API de bibliothèque que nous ne pouvons pas modifier). L'API utilise un pointeur de fonction pour appeler la fonction définie par l'utilisateur appropriée.
la source
Je vais essayer de donner une liste un peu complète ici:
Rappels : personnalisez certaines fonctionnalités (de bibliothèque) avec le code fourni par l'utilisateur. Le premier exemple est
qsort()
, mais aussi utile pour gérer les événements (comme un bouton appelant un rappel quand on clique dessus), ou nécessaire pour démarrer un thread (pthread_create()
).Polymorphisme : La vtable dans une classe C ++ n'est rien d'autre qu'une table de pointeurs de fonction. Et un programme C peut également choisir de fournir une table virtuelle pour certains de ses objets:
Le constructeur de
Derived
définirait alors savtable
variable membre sur un objet global avec les implémentations de la classe dérivée dedestruct
etfrobnicate
, et le code nécessaire pour détruire unstruct Base*
appellerait simplementbase->vtable->destruct(base)
, qui appellerait la version correcte du destructeur, indépendamment de la classe dérivéebase
réellement vers .Sans pointeurs de fonction, le polymorphisme devrait être codé avec une armée de constructions de commutateurs comme
Cela devient assez peu maniable assez rapidement.
Code chargé dynamiquement : Lorsqu'un programme charge un module en mémoire et tente d'appeler son code, il doit passer par un pointeur de fonction.
Toutes les utilisations de pointeurs de fonction que j'ai vues tombent carrément dans l'une de ces trois grandes classes.
la source