{"id":22180191,"url":"https://github.com/bts-lasalle-avignon-ressources/callback","last_synced_at":"2026-05-10T09:38:26.207Z","repository":{"id":223111532,"uuid":"759311309","full_name":"bts-lasalle-avignon-ressources/callback","owner":"bts-lasalle-avignon-ressources","description":"Les fonctions de rappel en C/C++, Java et ESP32","archived":false,"fork":false,"pushed_at":"2024-02-18T09:45:22.000Z","size":44,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-29T23:29:34.075Z","etag":null,"topics":["cpp","esp32","java"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bts-lasalle-avignon-ressources.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-02-18T08:26:44.000Z","updated_at":"2024-02-18T09:47:30.000Z","dependencies_parsed_at":"2024-02-18T11:45:00.895Z","dependency_job_id":null,"html_url":"https://github.com/bts-lasalle-avignon-ressources/callback","commit_stats":null,"previous_names":["bts-lasalle-avignon-ressources/callback"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bts-lasalle-avignon-ressources%2Fcallback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bts-lasalle-avignon-ressources%2Fcallback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bts-lasalle-avignon-ressources%2Fcallback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bts-lasalle-avignon-ressources%2Fcallback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bts-lasalle-avignon-ressources","download_url":"https://codeload.github.com/bts-lasalle-avignon-ressources/callback/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245331453,"owners_count":20597975,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","esp32","java"],"created_at":"2024-12-02T09:17:24.700Z","updated_at":"2026-05-10T09:38:21.174Z","avatar_url":"https://github.com/bts-lasalle-avignon-ressources.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fonction de rappel (_callback_)\n\n- [Fonction de rappel (_callback_)](#fonction-de-rappel-callback)\n  - [Présentation](#présentation)\n  - [Utilisation](#utilisation)\n  - [Adresse d'une fonction](#adresse-dune-fonction)\n    - [Langage C](#langage-c)\n    - [Langage C++](#langage-c-1)\n  - [Exemples](#exemples)\n    - [Fonction de rappel en C/C++](#fonction-de-rappel-en-cc)\n    - [Fonction de rappel en C++11](#fonction-de-rappel-en-c11)\n    - [Méthode de rappel en C++11](#méthode-de-rappel-en-c11)\n    - [ESP32 avec la plateforme Arduino](#esp32-avec-la-plateforme-arduino)\n  - [POO (Programmation Orientée Objet)](#poo-programmation-orientée-objet)\n    - [C++](#c)\n    - [Java et Android](#java-et-android)\n    - [ESP32 avec la plateforme Arduino](#esp32-avec-la-plateforme-arduino-1)\n  - [Auteurs](#auteurs)\n\n---\n\n## Présentation\n\nUne [fonction de rappel](https://fr.wikipedia.org/wiki/Fonction_de_rappel) (_callback_) ou fonction de post-traitement est une fonction qui est passée en argument à une autre fonction. Cette dernière peut alors faire usage de cette fonction de rappel comme de n'importe quelle autre fonction, alors qu'elle ne la connaît pas par avance. (Wikipédia)\n\n\u003e [!TIP]\n\u003e La technique de la fonction de rappel s'inspire du principe d'Hollywood (ou [Inversion de contrôle](https://fr.wikipedia.org/wiki/Inversion_de_contr%C3%B4le)) où l'appelant laisse ses coordonnées pour pouvoir être rappelé par la suite : « Ne nous appelez pas, c'est nous qui vous appellerons ».\n\n## Utilisation\n\nLes fonctions de rappel sont notamment utilisées dans la programmation évènementielle.\n\n\u003e [!TIP]\n\u003e Les fonctions de rappel sont très présentes dans les _frameworks_ (pour [l'inversion de contrôle](https://fr.wikipedia.org/wiki/Inversion_de_contr%C3%B4le)). Qt utilise par exemple le mécanisme signal/slot et Java/Android les _listeners_.\n\nElles sont aussi très utilisées en programmation système et notamment en langage C.\n\nEn programmation orientée objet (POO), la technique de rappel évolue en pouvant passer en paramètre un objet (qui se conformera à une interface donnée). L'objet pourra alors encapsuler plusieurs fonctions de rappel.\n\n\u003e [!NOTE]\n\u003e Le fait de passer un objet permet de contextualiser en indiquant sur **quoi** s'effectue le rappel, tandis qu'une fonction de rappel précisait seulement **comment** rappeler. Cependant la technique des fonctions de rappel continue à avoir les faveurs des langages disposant de [fermetures](https://fr.wikipedia.org/wiki/Fermeture_(informatique)), où celles-ci offrent des capacités équivalentes aux objets en termes de contexte. Source : [wikipedia](https://fr.wikipedia.org/wiki/Fonction_de_rappel)\n\n## Adresse d'une fonction\n\n### Langage C\n\n\u003e [!IMPORTANT]\n\u003e En langage C, on manipule les adresses avec des variables (spéciales) de type **pointeur**.\n\nUn **pointeur sur une fonction** correspondra à l'adresse du début du code de la fonction.\n\nLe nom d’une fonction est donc une **constante de type pointeur** :\n\n```cpp\n// définition d'une fonction :\nint f(int x, int y)\n{\n    return x+y;\n}\n\n// déclaration d'un pointeur sur une fonction :\nint (*pf)(int, int);\n\n// pf est un pointeur vers une fonction admettant 2 entiers en paramètres et retournant un entier, donc\n// on peut faire \"pointer\" pf sur la fonction f\npf = f;\n\n// un appel en utilisant le pointeur pf (qui contient l'adresse de f) :\nprintf(\"%d\\n\", (*pf)(3, 5)); // affiche 8\n```\n\nLes pointeurs sur les fonctions sont notamment utilisés dans la fonction `qsort` qui permet le tri des éléments d'un tableau et dans la recherche dichotomique d'un tableau trié avec `bsearch`. Ces deux fonctions sont définies dans la bibliothèque standard :\n\n```bash\n$ man qsort\nNOM\n     qsort - Trier un tableau\n\nSYNOPSIS\n     #include \u003cstdlib.h\u003e\n\n     void qsort(void *base, size_t nmemb, size_t size,\n                int (*compar)(const void *, const void *));\n\nDESCRIPTION\n     La fonction qsort() trie un tableau contenant nmemb éléments de taille size.\n     L'argument base pointe sur le début du tableau.\n\n     Le  contenu du tableau est trié en ordre croissant, en utilisant la fonction de comparaison pointée par compar, laquelle est appelée avec deux arguments pointant sur les objets à comparer.\n\n     La fonction de comparaison doit renvoyer un entier inférieur, égal, ou supérieur à zéro si le premier argument est respectivement considéré comme inférieur, égal ou supérieur au second. Si la comparaison des deux arguments renvoie une égalité (valeur de retour nulle), l'ordre des deux éléments est indéfini.\n...\n\n$ man bsearch\nNOM\n     bsearch - Recherche dichotomique dans un tableau trié\n\nSYNOPSIS\n     #include \u003cstdlib.h\u003e\n\n     void *bsearch(const void *key, const void *base,\n                   size_t nmemb, size_t size,\n                   int (*compar)(const void *, const void *));\n\nDESCRIPTION\n    La fonction bsearch() recherche l'objet correspondant à key, dans un tableau de nmemb objets, commençant à l'adresse base. La taille de chaque élément du tableau est indiquée dans size.\n\n    Le contenu du tableau doit être trié en ordre croissant par rapport à la fonction de comparaison référencée par compar. La routine compar doit être capable de recevoir deux arguments, le premier pointant sur l'objet key, et le second sur un élément du tableau (l'ordre des arguments est toujours respecté par bsearch).\n\n    Cette routine doit retourner une valeur entière respectivement inférieure, égale ou supérieure à zéro si l'objet key est inférieur, égal, ou supérieur à l'élément du tableau.\n```\n\nLes pointeurs sur les fonctions sont aussi utilisés dans la création d'un _thread_ :\n\n```bash\n$ man pthread_create\nNOM\n    pthread_create - Créer un nouveau thread\n\nSYNOPSIS\n    #include \u003cpthread.h\u003e\n\n    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,\n                       void *(*start_routine) (void *), void *arg);\n\n    Compilez et effectuez l'édition des liens avec l'option -pthread.\n\nDESCRIPTION\n    La  fonction pthread_create()  démarre un nouveau thread dans le processus appelant. Le nouveau thread commence par appeler start_routine() ; arg est passé comme unique argument de start_routine().\n...\n```\n\nOn retrouve aussi les pointeurs de fonction sur la plateforme Arduino pour installer un gestionnaire d'interruption avec la fonction `attachInterrupt()` (voir [FunctionalInterrupt.cpp](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/FunctionalInterrupt.cpp)).\n\nDeux exemples simples :\n\n```cpp\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n\nint somme(int, int);\nint produit(int, int);\nint operation(int, int, int(*)(int, int));\n\nint somme(int a, int b)\n{\n    return (a + b);\n}\n\nint produit(int a, int b)\n{\n    return (a * b);\n}\n\nint operation(int a, int b, int (*f)(int, int))\n{\n    return ((*f)(a, b));\n}\n\nint main(int argc, char *argv[])\n{\n    int a = 2, b = 3;\n\n    printf(\"%d + %d = %d\\n\", a, b, operation(a, b, somme));\n    printf(\"%d x %d = %d\\n\", a, b, operation(a, b, produit));\n\n    return 0;\n}\n```\n\n```cpp\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cstdbool.h\u003e\n\nint rechercher(int t[], size_t taille, bool (*callback)(int element, int valeur), int valeur)\n{\n    for(int i = 0; i \u003c taille; i++)\n    {\n        if(callback(t[i], valeur))\n            return i;\n    }\n\n    return -1;\n}\n\nbool egale(int element, int valeur)\n{\n    if(element == valeur)\n    {\n        return true;\n    }\n\n    return false;\n}\n\nbool plusGrande(int element, int valeur)\n{\n    if(element \u003e valeur)\n    {\n        return true;\n    }\n\n    return false;\n}\n\nbool plusPetite(int element, int valeur)\n{\n    if(element \u003c valeur)\n    {\n        return true;\n    }\n\n    return false;\n}\n\nint main(int argc, char *argv[])\n{\n    const int taille = 5;\n    int t[] = {1, 2, 3, 4, 5};\n\n    printf(\"== 2 ? position = %d\\n\", rechercher(t, taille, egale, 2));\n    printf(\"\u003e 2 ? position = %d\\n\", rechercher(t, taille, plusGrande, 2));\n    printf(\"\u003c 2 ? position = %d\\n\", rechercher(t, taille, plusPetite, 2));\n\n    return 0;\n}\n```\n\n### Langage C++\n\n\u003e [!NOTE]\n\u003e Créé initialement par **Bjarne Stroustrup** dans les années 1980, le langage C++ est aujourd'hui normalisé par l'ISO. Sa première normalisation date de **1998** (ISO/CEI 14882:1998), ensuite amendée par l'erratum technique de **2003** (ISO/CEI 14882:2003). Une importante mise à jour a été ratifiée et publiée par l'ISO en septembre 2011 sous le nom de ISO/IEC 14882:2011, ou **C++11**. Depuis, des mises à jour sont publiées régulièrement : en 2014 (ISO/CEI 14882:2014 ou C++14) puis en 2017 (ISO/CEI 14882:2017 ou C++17).  Source : [wikipedia.org](https://fr.wikipedia.org/wiki/C%2B%2B)\n\nEn C++, la mise en oeuvre des pointeurs de fonction et de méthodes avec `std::function` et `std::mem_fn` est apparue avec la mise à jour **C++11**.\n\n\u003e [!WARNING]\n\u003e En C++, seules les **méthodes statiques** (les fonctions directement accessible à partir de la classe) ont une adresse mémoire au moment de la compilation.\n\n`std::function` permet d'encapsuler un pointeur de fonction :\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cfunctional\u003e\n\nusing namespace std;\n\nvoid foo(string str)\n{\n    cout \u003c\u003c \"message : \" \u003c\u003c str \u003c\u003c endl;\n}\n\nint main()\n{\n    std::function\u003cvoid(string)\u003e fn_foo = foo;\n\n    fn_foo(\"Hello world!\");\n\n    return 0;\n}\n```\n\n`std::mem_fn` permet d'encapsuler un pointeur de méthode (une fonction membre) d'une classe :\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cfunctional\u003e\n\nusing namespace std;\n\nclass Foo\n{\n    public:\n        Foo(const string\u0026 str) : str(str) {}\n        void print(int n=1) const { for(int i = 0; i\u003cn; ++i) cout \u003c\u003c str \u003c\u003c '\\n'; }\n    private:\n        string str;\n};\n\nint main()\n{\n    const Foo foo(\"Hello world!\");\n\n    auto fn1 = mem_fn(\u0026Foo::print);\n    fn1(foo, 5);\n\n    return 0;\n}\n```\n\nCompilation :\n\n```bash\n$ g++ -std=c++11 xxxxxxxx.cpp\n```\n\nLiens :\n\n- [std::function](http://www.cplusplus.com/reference/functional/function/)\n- [std::mem_fn](http://www.cplusplus.com/reference/functional/mem_fn/)\n\nVoir aussi :\n\n- [std::bind](http://www.cplusplus.com/reference/functional/bind/)\n\n## Exemples\n\n### Fonction de rappel en C/C++\n\nUn squelette pour une utilisation avec un pointeur de fonction :\n\n```cpp\n#include \u003ciostream\u003e // pour std::cout\n\nclass Foo\n{\n  public:\n    Foo();\n    ~Foo();\n\n    void traiter();\n    void setCallback( void (*f)() );\n    void onEvent();\n\n  private:\n    void (*_callback)();\n};\n\nFoo::Foo() : _callback(nullptr)\n{\n}\n\nFoo::~Foo()\n{\n}\n\nvoid Foo::traiter()\n{\n    // Effectue le traitement et\n    // SI condition ALORS on déclenche le rappel ...\n    onEvent();\n}\n\nvoid Foo::setCallback( void (*f)() )\n{\n    _callback = f;\n}\n\n// L'évènement Event déclenchera l'appel à callback\nvoid Foo::onEvent()\n{\n    if ( _callback != nullptr)\n    {\n        _callback();\n    }\n}\n\n// La fonction de rappel\nvoid fonctionRappel()\n{\n    // ...\n    std::cout \u003c\u003c __FUNCTION__ \u003c\u003c std::endl;\n}\n\nint main()\n{\n    // Instancie un objet\n    Foo foo;\n\n    // Installe la fonction de rappel\n    foo.setCallback(fonctionRappel);\n\n    // Réalise un traitement\n    foo.traiter();\n\n    return 0;\n}\n```\n\n### Fonction de rappel en C++11\n\nUn squelette pour une utilisation avec `std::function` :\n\n```cpp\n#include \u003ciostream\u003e // pour std::cout\n#include \u003cfunctional\u003e // pour std::function\n\nclass Foo\n{\n  public:\n    Foo();\n    ~Foo();\n\n    void traiter();\n    void setCallback( std::function\u003cvoid()\u003e f );\n    void onEvent();\n\n  private:\n    std::function\u003cvoid()\u003e _callback;\n};\n\nFoo::Foo() : _callback(nullptr)\n{\n}\n\nFoo::~Foo()\n{\n}\n\nvoid Foo::traiter()\n{\n    // Effectue le traitement et\n    // SI condition ALORS on déclenche le rappel ...\n    onEvent();\n}\n\nvoid Foo::setCallback( std::function\u003cvoid()\u003e f )\n{\n    _callback = f;\n}\n\n// L'évènement Event déclenchera l'appel à callback\nvoid Foo::onEvent()\n{\n    if ( _callback != nullptr)\n    {\n        _callback();\n    }\n}\n\n// La fonction de rappel\nvoid fonctionRappel()\n{\n    // ...\n    std::cout \u003c\u003c __FUNCTION__ \u003c\u003c std::endl;\n}\n\nint main()\n{\n    // Instancie un objet\n    Foo foo;\n\n    // Installe la fonction de rappel\n    foo.setCallback(fonctionRappel);\n\n    // Réalise un traitement\n    foo.traiter();\n\n    return 0;\n}\n```\n\n### Méthode de rappel en C++11\n\nUn squelette pour une utilisation avec `std::bind` :\n\n```cpp\n#include \u003ciostream\u003e // pour std::cout\n#include \u003cfunctional\u003e // pour std::function et std::bind\n\nclass Foo\n{\n  public:\n    Foo();\n    ~Foo();\n\n    void traiter();\n    void setCallback( std::function\u003cvoid()\u003e f );\n    void onEvent();\n\n  private:\n    std::function\u003cvoid()\u003e _callback;\n};\n\nFoo::Foo() : _callback(nullptr)\n{\n}\n\nFoo::~Foo()\n{\n}\n\nvoid Foo::traiter()\n{\n    // Effectue le traitement et\n    // SI condition ALORS on déclenche le rappel ...\n    onEvent();\n}\n\nvoid Foo::setCallback( std::function\u003cvoid()\u003e f )\n{\n    _callback = f;\n}\n\n// L'évènement Event déclenchera l'appel à callback\nvoid Foo::onEvent()\n{\n    if ( _callback != nullptr)\n    {\n        _callback();\n    }\n}\n\nclass Bar\n{\n    public:\n        Bar() { }\n        void methodeRappel();\n};\n\n// La méthode de rappel\nvoid Bar::methodeRappel()\n{\n    // ...\n    std::cout \u003c\u003c __FUNCTION__ \u003c\u003c std::endl;\n}\n\nint main()\n{\n    // Instancie un objet\n    Foo foo;\n\n    // Installe le rappel\n    foo.setCallback(std::bind(\u0026Bar::methodeRappel, new Bar()));\n    // ou :\n    //Bar bar;\n    //foo.setCallback(std::bind(\u0026Bar::methodeRappel, \u0026bar));\n\n    // Réalise un traitement\n    foo.traiter();\n\n    return 0;\n}\n```\n\n### ESP32 avec la plateforme Arduino\n\n\u003e [!NOTE]\n\u003e On retrouve les pointeurs de fonction sur la plateforme Arduino pour installer un gestionnaire d'interruption avec la fonction `attachInterrupt()` (voir [FunctionalInterrupt.cpp](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/FunctionalInterrupt.cpp)).\n\nExemple d'utilisation d'un gestionnaire d'interruption sous forme de méthode d'une classe :\n\n```cpp\n#include \u003cArduino.h\u003e\n#include \u003cFunctionalInterrupt.h\u003e // pour std::bind\n\n// Brochage\n#define GPIO_SW1 12\n\nclass TestInterrupt\n{\n  private:\n    volatile int nb; // volatile si a est utilisé par le gestionnaire d'interruption\n\n  public:\n    TestInterrupt() { nb = 0; }\n    int getNb() const { return nb; }\n    void IRAM_ATTR routine();\n};\n\nvoid IRAM_ATTR TestInterrupt::routine()\n{\n  ++nb;\n}\n\nTestInterrupt testInterrupt;\n\nvoid setup()\n{\n  Serial.begin(115200);\n  while (!Serial);\n\n  pinMode(GPIO_SW1, INPUT_PULLUP);\n\n  attachInterrupt(digitalPinToInterrupt(GPIO_SW1), std::bind(\u0026TestInterrupt::routine, \u0026testInterrupt), FALLING);\n}\n\nvoid loop()\n{\n  if(testInterrupt.getNb() \u003e 0)\n  {\n    Serial.print(\"\u003cloop\u003e nb=\"); Serial.print(testInterrupt.getNb()); Serial.println();\n  }\n  else\n  {\n    Serial.print(\".\");\n  }\n\n  delay(1000);\n}\n```\n\n## POO (Programmation Orientée Objet)\n\nEn programmation orientée objet (POO), la technique de rappel peut évoluer en passant en paramètre un objet qui se conformera à une interface donnée. L'objet pourra alors encapsuler plusieurs fonctions de rappel.\n\n### C++\n\nEn C++, on pourra utiliser le concept de **classe abstraite** et **encapsuler plusieurs fonctions de rappel** en utilisant les **méthodes virtuelles pures** :\n\n```cpp\n#include \u003ciostream\u003e\n#include \u003cfunctional\u003e\n\nclass FooAbstractListener\n{\n    public:\n        virtual void onEvent() = 0;\n        virtual void onError() = 0;\n};\n\nclass Foo\n{\n    public:\n        Foo();\n        ~Foo();\n        void traiter();\n        void setCallback(FooAbstractListener *callback);\n\n    private:\n        FooAbstractListener *callback; // Pour les fonctions de rappel sur évènement (onEvent, onError, ...)\n\n};\n\nFoo::Foo() : callback(nullptr)\n{\n}\n\nFoo::~Foo()\n{\n}\n\nvoid Foo::traiter()\n{\n    // Effectue le traitement et\n    // SI condition ALORS on déclenche le rappel ...\n    if(callback != nullptr)\n    {\n        callback-\u003eonEvent();\n    }\n}\n\nvoid Foo::setCallback(FooAbstractListener *callback)\n{\n    this-\u003ecallback = callback;\n}\n\nclass FooListener : public FooAbstractListener\n{\n    public:\n        void onEvent();\n        void onError();\n};\n\n// La méthode de rappel déclenchée sur évènement\nvoid FooListener::onEvent()\n{\n    // ...\n    std::cout \u003c\u003c __FUNCTION__ \u003c\u003c std::endl;\n}\n\n// La méthode de rappel déclenchée sur l'évènement erreur\nvoid FooListener::onError()\n{\n    // ...\n    std::cout \u003c\u003c __FUNCTION__ \u003c\u003c std::endl;\n}\n\nint main()\n{\n    // Instancie un objet\n    Foo foo;\n\n    // Installe les fonctions de rappel\n    foo.setCallback(new FooListener());\n\n    // Réalise un traitement\n    foo.traiter();\n\n    return 0;\n}\n```\n\n### Java et Android\n\nEn Java, on pourra utiliser le concept d'**interface** et **encapsuler plusieurs fonctions de rappel** :\n\n```java\npublic interface FooListener\n{\n    public void onEvent();\n    public void onError();\n}\n```\n\n```java\npublic class Foo\n{\n    private FooListener callback; // Pour les fonctions de rappel sur évènement (onEvent, onError, ...)\n\n    /**\n     * Installe les fonctions de rappel pour les évènements onEvent, ...\n     */\n    public void setCallback(FooListener callback)\n    {\n        this.callback = callback;\n    }\n\n    public void traiter()\n    {\n        // Effectue le traitement et\n        // SI condition ALORS on déclenche le rappel ...\n        if(callback != null)\n        {\n            callback.onEvent();\n        }\n    }\n}\n```\n\nUne utilisation :\n\n```java\n// Instancie un objet\nfoo = new Foo();\n\n// Installe les fonctions de rappel\nfoo.setCallback(new FooListener()\n{\n    // Déclenchée sur évènement\n    public void onEvent()\n    {\n        // ...\n    }\n\n    // Déclenchée sur l'évènement erreur\n    public void onError()\n    {\n        // ...\n    }\n});\n\n// Réalise un traitement\nfoo.traiter();\n```\n\n### ESP32 avec la plateforme Arduino\n\nOn souhaite réaliser son propre serveur web en héritant de la classe [WebServer](https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/src/WebServer.h)  :\n\n```cpp\n#include \u003cWebServer.h\u003e\n\n#define PORT_SERVEUR_WEB 80\n\nclass ServeurWeb : public WebServer\n{\nprivate:\n    void afficherAccueil();\n    void traiterRequeteNonTrouvee();\n\npublic:\n    ServeurWeb();\n    void demarrer();\n    void traiterRequetes();\n};\n```\n\nExtrait de la classe [WebServer](https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/src/WebServer.h) :\n\n```cpp\nclass WebServer\n{\npublic:\n    //...\n    typedef std::function\u003cvoid(void)\u003e THandlerFunction;\n\n    void on(const Uri \u0026uri, THandlerFunction fn);\n    void on(const Uri \u0026uri, HTTPMethod method, THandlerFunction fn);\n    void on(const Uri \u0026uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); //ufn handles file uploads\n    void onNotFound(THandlerFunction fn);  //called when handler is not assigned\n    //...\n};\n```\n\n\u003e [!IMPORTANT]\n\u003e Les explications sur l'utilisation de `std::function` sont fournies dans cette [partie](#langage-c-1).\n\nLes méthodes `on()` et `onNotFound()` attendent en paramètre la **fonction de rappel** qui sera déclenchée lors d'une requête HTTP et qui en assurera le traitement.\n\nMais les fonctions de rappel sont déclarées dans la classe `ServeurWeb` (`afficherAccueil()` par exemple) et cela pose un problème en C++ : les fonctions déclarées au sein d'une classe sont nommées des fonctions membres ou **méthodes**. Et ces méthodes n’existeront **seulement** lors de l'instanciation d'un objet de cette classe.\n\nLa solution est d'utiliser l'appel `bind()` pour obtenir l'**adresse de la méthode d'un objet**. La fonction `bind()` reçoit en paramètre la méthode (`\u0026ServeurWeb::afficherAccueil` par exemple) et l'adresse de l'objet (ici `this`) qui la possède et retourne l'adresse de cette méthode.\n\nL'appel `bind()` permet d'utiliser les méthodes d'une classe comme fonction de rappel :\n\n```cpp\nServeurWeb::ServeurWeb() :  WebServer(PORT_SERVEUR_WEB)\n{\n}\n\nvoid ServeurWeb::demarrer()\n{\n    // Installe les gestionnaires de requêtes\n    on(\"/\", HTTP_GET, std::bind(\u0026ServeurWeb::afficherAccueil, this));\n    onNotFound(std::bind(\u0026ServeurWeb::traiterRequeteNonTrouvee, this));\n\n    // Démarre le serveur\n    begin();\n}\n\nvoid ServeurWeb::traiterRequetes()\n{\n    handleClient();\n}\n\nvoid ServeurWeb::afficherAccueil()\n{\n    String message = \"\u003ch1\u003eBienvenue ...\u003c/h1\u003e\\n\";\n    message += \"\u003cp\u003eLaSalle Avignon v1.0\u003c/p\u003e\\n\";\n    send(200, F(\"text/html\"), message);\n}\n\nvoid ServeurWeb::traiterRequeteNonTrouvee()\n{\n    String message = \"404 File Not Found\\n\\n\";\n    message += \"URI: \";\n    message += uri();\n    message += \"\\nMethod: \";\n    message += (method() == HTTP_GET) ? \"GET\" : \"POST\";\n    message += \"\\nArguments: \";\n    message += args();\n    message += \"\\n\";\n    for(uint8_t i = 0; i \u003c args(); i++)\n    {\n        message += \" \" + argName(i) + \": \" + arg(i) + \"\\n\";\n    }\n    send(404, \"text/plain\", message);\n}\n```\n\n## Auteurs\n\n- [Thierry VAIRA](thierry.vaira@gmail.com) : [tvaira.free.fr](http://tvaira.free.fr/)\n\n---\n©️ 2021 BTS LaSalle Avignon\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbts-lasalle-avignon-ressources%2Fcallback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbts-lasalle-avignon-ressources%2Fcallback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbts-lasalle-avignon-ressources%2Fcallback/lists"}