C++

Fonction de rappel en C++

Fonction de rappel en C++

Une fonction de rappel est une fonction, qui est un argument, pas un paramètre, dans une autre fonction. L'autre fonction peut être appelée la fonction principale. Deux fonctions sont donc impliquées : la fonction principale et la fonction de rappel elle-même. Dans la liste des paramètres de la fonction principale, la déclaration de la fonction de rappel sans sa définition est présente, tout comme les déclarations d'objet sans affectation sont présentes. La fonction principale est appelée avec des arguments (dans main()). L'un des arguments de l'appel de fonction principale est la définition effective de la fonction de rappel. En C++, cet argument est une référence à la définition de la fonction de rappel ; ce n'est pas la vraie définition. La fonction de rappel elle-même est en fait appelée dans la définition de la fonction principale.

La fonction de rappel de base en C++ ne garantit pas un comportement asynchrone dans un programme.  Le comportement asynchrone est le véritable avantage du schéma de fonction de rappel. Dans le schéma de fonction de rappel asynchrone, le résultat de la fonction principale doit être obtenu pour le programme avant que le résultat de la fonction de rappel ne soit obtenu. Il est possible de le faire en C++ ; cependant, C++ a une bibliothèque appelée future pour garantir le comportement du schéma de fonction de rappel asynchrone.

Cet article explique le schéma de base de la fonction de rappel. C'est en grande partie avec du C pur++. En ce qui concerne le rappel, le comportement de base de la future bibliothèque est également expliqué. Des connaissances de base en C++ et ses pointeurs sont nécessaires à la compréhension de cet article.

Contenu de l'article

Schéma de fonction de rappel de base

Un schéma de fonction de rappel a besoin d'une fonction principale et de la fonction de rappel elle-même. La déclaration de la fonction de rappel fait partie de la liste des paramètres de la fonction principale. La définition de la fonction de rappel est indiquée dans l'appel de fonction de la fonction principale. La fonction de rappel est en fait appelée dans la définition de la fonction principale. Le programme suivant illustre cela :

#inclure
en utilisant l'espace de noms std ;
int principalFn(char ch[], int (*ptr)(int))

entier id1 = 1;
entier id2 = 2;
int idr = (*ptr)(id2);
cout<<"principal function: "<renvoyer id1 ;

int cb(int iden)

cout<<"callback function"<<'\n';
retour iden;

int main()

entier (*ptr)(int) = &cb;
char cha[] = "et";
principalFn(cha, cb);
renvoie 0 ;

La sortie est :

fonction de rappel
fonction principale : 1 et 2

La fonction principale est identifiée par principalFn(). La fonction de rappel est identifiée par cb(). La fonction de rappel est définie en dehors de la fonction principale mais en réalité appelée dans la fonction principale.

Notez la déclaration de la fonction de rappel en paramètre dans la liste des paramètres de la déclaration de la fonction principale. La déclaration de la fonction de rappel est "int (*ptr)(int)". Notez l'expression de la fonction de rappel, comme un appel de fonction, dans la définition de la fonction principale ; tout argument pour l'appel de la fonction de rappel y est passé. L'instruction pour cet appel de fonction est :

int idr = (*ptr)(id2);

Où id2 est un argument. ptr fait partie du paramètre, un pointeur, qui sera lié à la référence de la fonction de rappel dans la fonction main().

Notez l'expression :

entier (*ptr)(int) = &cb;

Dans la fonction main(), qui lie la déclaration (sans définition) de la fonction de rappel au nom de la définition de la même fonction de rappel.

La fonction principale est appelée, dans la fonction main(), comme :

principalFn(cha, cb);

Où cha est une chaîne et cb est le nom de la fonction de rappel sans aucun de ses arguments.

Comportement synchrone de la fonction de rappel

Considérez le programme suivant :

#inclure
en utilisant l'espace de noms std ;
void principalFn(void (*ptr)())

cout<<"principal function"<<'\n';
(*ptr)();

annuler cb()

cout<<"callback function"<<'\n';

vide fn()

cout<<"seen"<<'\n';

int main()

vide (*ptr)() = &cb;
principalFn(cb);
fn();
renvoie 0 ;

La sortie est :

fonction principale
fonction de rappel
vu

Il y a une nouvelle fonction ici. Tout ce que la nouvelle fonction fait, c'est d'afficher la sortie, "vu". Dans la fonction main(), la fonction principale est appelée, puis la nouvelle fonction, fn() est appelée. La sortie montre que le code de la fonction principale a été exécuté, puis celui de la fonction de rappel a été exécuté, et enfin celui de la fonction fn() a été exécuté. Il s'agit d'un comportement synchrone (à thread unique).

S'il s'agissait d'un comportement asynchrone, lorsque trois segments de code sont appelés dans l'ordre, le premier segment de code peut être exécuté, suivi à la place de l'exécution du troisième segment de code, avant que le deuxième segment de code ne soit exécuté.

Eh bien, la fonction fn() peut être appelée à partir de la définition de la fonction principale, au lieu de la fonction main(), comme suit :

#inclure
en utilisant l'espace de noms std ;
vide fn()

cout<<"seen"<<'\n';

void principalFn(void (*ptr)())

cout<<"principal function"<<'\n';
fn();
(*ptr)();

annuler cb()

cout<<"callback function"<<'\n';

int main()

vide (*ptr)() = &cb;
principalFn(cb);
renvoie 0 ;

La sortie est :

fonction principale
vu
fonction de rappel

Ceci est une imitation du comportement asynchrone. Ce n'est pas un comportement asynchrone. C'est toujours un comportement synchrone.

De plus, l'ordre d'exécution du segment de code de la fonction principale et du segment de code de la fonction de rappel peut être interverti dans la définition de la fonction principale. Le programme suivant illustre cela :

#inclure
en utilisant l'espace de noms std ;
 
void principalFn(void (*ptr)())

(*ptr)();
cout<<"principal function"<<'\n';

annuler cb()

cout<<"callback function"<<'\n';

vide fn()

cout<<"seen"<<'\n';

int main()

vide (*ptr)() = &cb;
principalFn(cb);
fn();
renvoie 0 ;

La sortie est maintenant,

fonction de rappel
fonction principale
vu

C'est aussi une imitation du comportement asynchrone. Ce n'est pas un comportement asynchrone. C'est toujours un comportement synchrone. Un véritable comportement asynchrone peut être obtenu comme expliqué dans la section suivante ou avec la bibliothèque, future.

Comportement asynchrone avec fonction de rappel

Le pseudo-code du schéma de fonction de rappel asynchrone de base est :

sortie de type ;
tapez cb (type sortie)

//déclarations

tapez principalFn(tapez entrée, tapez cb(tapez sortie))

//déclarations

Noter les positions des données d'entrée et de sortie aux différents endroits du pseudo-code. L'entrée de la fonction de rappel est sa sortie. Les paramètres de la fonction principale sont le paramètre d'entrée du code général et le paramètre de la fonction de rappel. Avec ce schéma, une troisième fonction peut être exécutée (appelée) dans la fonction main() avant que la sortie de la fonction de rappel ne soit lue (toujours dans la fonction main()). Le code suivant illustre cela :

#inclure
en utilisant l'espace de noms std ;
char *sortie;
void cb(char out[])

sortie = sortie ;

void principalFn(char input[], void (*ptr)(char[50]))

(*ptr)(entrée);
cout<<"principal function"<<'\n';

vide fn()

cout<<"seen"<<'\n';

int main()

char input[] = "fonction de rappel" ;
void (*ptr)(char[]) = &cb;
principalFn(entrée, cb);
fn();
cout<renvoie 0 ;

La sortie du programme est :

fonction principale
vu
fonction de rappel

Dans ce code particulier, la donnée de sortie et la donnée d'entrée se trouvent être la même donnée. Le résultat du troisième appel de fonction dans la fonction main() a été affiché avant le résultat de la fonction de rappel. La fonction de rappel exécutée, terminée et affectée son résultat (valeur) à la variable, sortie, permettant au programme de continuer sans son interférence. Dans la fonction main(), la sortie de la fonction de rappel était utilisée (lue et affichée) lorsque cela était nécessaire, conduisant à un comportement asynchrone pour l'ensemble du schéma.

C'est le moyen monothread d'obtenir un comportement asynchrone de la fonction de rappel avec du C pur++.

Utilisation de base de la future bibliothèque

L'idée du schéma de fonction de rappel asynchrone est que la fonction principale retourne avant que la fonction de rappel ne retourne. Cela a été fait indirectement, efficacement, dans le code ci-dessus.

Notez à partir du code ci-dessus que la fonction de rappel reçoit l'entrée principale du code et produit la sortie principale du code. La bibliothèque C++, future, a une fonction appelée sync(). Le premier argument de cette fonction est la référence de la fonction de rappel ; le deuxième argument est l'entrée de la fonction de rappel. La fonction sync() retourne sans attendre la fin de l'exécution de la fonction de rappel mais permet à la fonction de rappel de se terminer. Cela fournit un comportement asynchrone. Alors que la fonction de rappel continue de s'exécuter, puisque la fonction sync() est déjà retournée, les instructions en dessous continuent de s'exécuter. C'est comme un comportement asynchrone idéal.

Le programme ci-dessus a été réécrit ci-dessous, en tenant compte de la future bibliothèque et de sa fonction sync() :

#inclure
#inclure
#inclure
en utilisant l'espace de noms std ;
futur production;
chaîne cb(chaîne stri)

retour stri;

void principalFn (entrée de chaîne)

sortie = async(cb, entrée);
cout<<"principal function"<<'\n';

vide fn()

cout<<"seen"<<'\n';

int main()

string input = string("fonction de rappel");
principalFn(entrée);
fn();
chaîne ret = sortie.obtenir(); // attend le retour du rappel si nécessaire
cout<renvoie 0 ;

La fonction sync() stocke enfin la sortie de la fonction de rappel dans le futur objet. La sortie attendue peut être obtenue dans la fonction main(), en utilisant la fonction membre get() du futur objet.

Conclusion

Une fonction de rappel est une fonction, qui est un argument, pas un paramètre, dans une autre fonction. Un schéma de fonction de rappel a besoin d'une fonction principale et de la fonction de rappel elle-même. La déclaration de la fonction de rappel fait partie de la liste des paramètres de la fonction principale. La définition de la fonction de rappel est indiquée dans l'appel de fonction de la fonction principale (dans main()). La fonction de rappel est en fait appelée dans la définition de la fonction principale.

Un schéma de fonction de rappel n'est pas nécessairement asynchrone. Pour être sûr que le schéma de la fonction de rappel est asynchrone, effectuez l'entrée principale du code, l'entrée de la fonction de rappel ; faire de la sortie principale du code, la sortie de la fonction de rappel ; stocker la sortie de la fonction de rappel dans une variable ou une structure de données. Dans la fonction main(), après avoir appelé la fonction principale, exécutez d'autres instructions de l'application. Lorsque la sortie de la fonction de rappel est nécessaire, dans la fonction main(), utilisez-la (lisez-la et affichez-la) puis.

Meilleurs émulateurs de console de jeu pour Linux
Cet article répertorie les logiciels d'émulation de console de jeu populaires disponibles pour Linux. L'émulation est une couche de compatibilité logi...
Meilleures distributions Linux pour les jeux en 2021
Le système d'exploitation Linux a parcouru un long chemin depuis son apparence originale, simple et basée sur le serveur. Ce système d'exploitation s'...
Comment capturer et diffuser votre session de jeu sur Linux
Dans le passé, jouer à des jeux n'était considéré qu'un passe-temps, mais avec le temps, l'industrie du jeu a connu une croissance énorme en termes de...