IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

pointeur sur fonction membre


Sujet :

C++

  1. #1
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut pointeur sur fonction membre
    Bonjour à tous,

    en C++, il est possible de transmettre une fonction par référence à une méthode (au sens de l'objet) ou a une autre fonction.

    Mais est-il possible de transmettre une méthode (au sens de l'objet) par référence?

    merci

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 052
    Points
    33 052
    Billets dans le blog
    4
    Par défaut
    kamoulox
    tu veux faire quoi ou tu crois que quoi n'est pas possible ?
    méthode = fonction donc tes 2 phrases sont identiques, et "au sens de l'objet" c'est sensé vouloir dire quoi ?

  3. #3
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut
    Citation Envoyé par Bousk Voir le message
    kamoulox
    Bonjour,

    Citation Envoyé par Bousk Voir le message
    tu veux faire quoi ou tu crois que quoi n'est pas possible ?
    Je voudrais savoir si donner une méthode en argument d'une fonction est possible, comme il est possible de le faire pour une fonction.

    Citation Envoyé par Bousk Voir le message
    méthode = fonction donc tes 2 phrases sont identiques, et "au sens de l'objet" c'est sensé vouloir dire quoi ?
    "Au sens de l'objet" avait pour but de préciser qu'il s'agit bien d'une méthode implémentée au sein d'une classe. Cette précaution oratoire était peut-être inutile, mais mon objectif était de me faire comprendre au mieux.

    Méthode != fonction. Une méthode est propre à une classe, ce que n'est pas une fonction. De plus, concernant le problème qui nous intéresse, j'ai vu plusieurs sources indiquant que pthread_create, par exemple, n'acceptait en argument que des méthodes statiques.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 052
    Points
    33 052
    Billets dans le blog
    4
    Par défaut
    Ce que t'appelles méthode c'est une fonction membre, et choisir l'un ou l'autre des noms est une nomenclature que chacun suit ou non et absolument pas un standard.
    La seule différence c'est leur signature.
    Et passer une fonction en paramètre c'est créer un foncteur.
    pthread_create c'est une lib en C où les fonctions membre n'existent pas. Ça prend ce que le C permet, des fonctions libres (ou static).

  5. #5
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Ce que t'appelles méthode c'est une fonction membre, et choisir l'un ou l'autre des noms est une nomenclature que chacun suit ou non et absolument pas un standard.
    La seule différence c'est leur signature.
    J'appelle méthode une méthode au sens de l'objet, et c'était très clair dans mon message.
    Et il n'y a pas qu'une différence de signature entre une fonction et une méthode au sens de l'objet.

    Citation Envoyé par Bousk Voir le message
    Et passer une fonction en paramètre c'est créer un foncteur.
    pthread_create c'est une lib en C où les fonctions membre n'existent pas. Ça prend ce que le C permet, des fonctions libres (ou static).
    Il y a beaucoup plus simple pour passer une fonction en paramètre: lui transmettre un pointeur sur cette fonction, c'est ce qui est fait dans le code que j'ai récupéré, et je réfléchis à la réécrire en objet.

    Citation Envoyé par Bousk Voir le message
    pthread_create c'est une lib en C où les fonctions membre n'existent pas. Ça prend ce que le C permet, des fonctions libres (ou static).
    S'il n'y avait pas de différence entre méthode et fonction en C++, pthread_create accepterait des méthodes en argument.

  6. #6
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    746
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 746
    Points : 3 664
    Points
    3 664
    Par défaut
    Il existe std::thread pour ne pas avoir à ce préoccuper de toute la gestion des pointeurs de fonction. Sinon, un simple intermédiaire comme ce qui suit suffit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    auto func = [](void* ctx) {
      static_cast<LeTypeVoulut*>(ctx).la_fonction();
      return ....
    };
    pthread_create(thread, attr, func, &obj);

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 483
    Points : 13 681
    Points
    13 681
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    J'appelle méthode une méthode au sens de l'objet
    En C++, on retrouve plutôt le terme de "fonction membre" (ou "member function", en anglais) que le terme de "méthode". Voir https://en.cppreference.com/w/cpp/la...mber_functions

    Je suppose que ton problème est : comment passer un couple [objet ; fonction membre] là où tu passes habituellement un simple pointeur sur fonction, non ?

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 483
    Points : 13 681
    Points
    13 681
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par foetus Voir le message
    static_cast n'a rien à voir avec la notion de statique.
    Lorsque tu fais 1 cast "à la C", tu fais soit 1 static_cast soit 1 reinterpret_cast, ce qui peut provoquer des pièges (il faut lire la norme pour le comment de la chose)
    En C++, tout est clair et il y en a 2 autres spécifiques au C++ const_cast et dynamic_cast.
    Pourquoi on parle de cast d'un seul coup ?

    const_cast est possible en C :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main() {
        const int a = 2;
        int * p = (int*) &a;
        *p = 45;
        return a;
    }
    Seul dynamic_cast est spécifique au C++.

  9. #9
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut
    Citation Envoyé par Bktero Voir le message
    En C++, on retrouve plutôt le terme de "fonction membre" (ou "member function", en anglais) que le terme de "méthode". Voir https://en.cppreference.com/w/cpp/la...mber_functions
    Ok, je retiens ce point de vocabulaire propre au C++.
    De mon coté, j'ai appris l'objet à la fois dans des ouvrages qui décrivent théoriquement le concept (et utilisent le terme méthode) et en python (avec un cours qui utilisait le terme méthode), ceci explique cela.

    Citation Envoyé par Bktero Voir le message
    Je suppose que ton problème est : comment passer un couple [objet ; fonction membre] là où tu passes habituellement un simple pointeur sur fonction, non ?
    C'est ça, voilà.
    Après cela pourrait aussi peut-être le faire avec ce que j'appelle une méthode de classe/méthode statique, à savoir une méthode de la classe qui n'est pas associée à une instance de cette classe (peut-être "fonction membre statique" en C++).

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 052
    Points
    33 052
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    J'appelle méthode une méthode au sens de l'objet, et c'était très clair dans mon message.
    Et il n'y a pas qu'une différence de signature entre une fonction et une méthode au sens de l'objet.



    Il y a beaucoup plus simple pour passer une fonction en paramètre: lui transmettre un pointeur sur cette fonction, c'est ce qui est fait dans le code que j'ai récupéré, et je réfléchis à la réécrire en objet.



    S'il n'y avait pas de différence entre méthode et fonction en C++, pthread_create accepterait des méthodes en argument.
    Si tu sais déjà tout pourquoi venir poser des questions alors ?
    C'est un nouveau concept de venir avec des questions, dire qu'en fait non on a raison et on sait mieux les réponses et surtout ne jamais présenter de code incriminé ?

    On utilisait pthread y'a 20 ans déjà, tout comme le C++, et les deux ensembles. Des ressources qui montrent comment faire sont légion sur internet pour qui veut bien chercher.
    Sur ce seul forum il y a des dizaines de résultats à ce sujet. Avec le simple "pthread_create", donc pas vraiment un terme caché ou obscur, pour faire ressortir des résultats probants.
    https://www.developpez.net/forums/d1.../#post10432689
    https://www.developpez.net/forums/d1...thread_create/
    https://www.developpez.net/forums/d1...e/#post8106791
    https://cpp.developpez.com/faq/cpp/?...ur-de-fonction
    https://www.developpez.net/forums/d1...s/#post7553057
    https://www.developpez.net/forums/d1...e/#post7552025
    https://www.developpez.net/forums/d1...ction-d-objet/

    Et maintenant on préfèrera le plus souvent std::thread qui est dans le standard depuis C++11.

  11. #11
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut
    Merci pour ton intervention.
    Je rajoute cependant que mon objectif n'est pas d'utiliser pthread_create, j'utilise std::thread effectivement. J'ai cité cet exemple pour illustrer une différence entre méthode et fonction (au sens que je donne à ces termes, mais il n'y a pas que moi quand même ).

    Moi j'ai simplement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    obj.fctMembre(&fct, &err);
    avec fct est est une fonction, et je voudrais savoir si je peux remplacer cette fonction par une fonction membre.

    voilà voilà

  12. #12
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 483
    Points : 13 681
    Points
    13 681
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Ok, je retiens ce point de vocabulaire propre au C++.
    De mon coté, j'ai appris l'objet à la fois dans des ouvrages qui décrivent théoriquement le concept (et utilisent le terme méthode) et en python (avec un cours qui utilisait le terme méthode), ceci explique cela..
    A ta décharge, je crois que tout le monde dit "méthode", sauf le C++

    Citation Envoyé par Chezkele Voir le message
    C'est ça, voilà.
    Après cela pourrait aussi peut-être le faire avec ce que j'appelle une méthode de classe/méthode statique, à savoir une méthode de la classe qui n'est pas associée à une instance de cette classe (peut-être "fonction membre statique" en C++).
    Si tu veux vraiment un pointeur sur fonction, alors ce ne sera pas possible. Il te faudra une fonction libre, une fonction membre statique, ou une lambda non capturante.

    Mais si tu utilises std::thread, tu n'es pas limité à un pointeur sur fonction. En regardant les constructeurs, on voit que la signature (sans doute) la plus utilisée est la 3e :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template< class Function, class... Args >
    explicit thread( Function&& f, Args&&... args );
    En dessous, on lit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f	-	Callable object to execute in the new thread
    Un Callable est plus beaucoup général qu'un pointeur sur fonction.

    Tu peux utiliser une lambda capturante (j'ai écrit un article plutôt complet sur les lambdas) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <iostream>
    #include <thread>
     
    struct Foo {
        void f() const {
            std::cout << "action!\n";
        }
    };
     
    int main() {
        Foo foo;
        auto lambda = [foo]() {
            foo.f();
        };
        std::thread thread{lambda};
        thread.join();
    }

    Tu peux utiliser un functor ou function objet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
    #include <thread>
     
    struct Foo {
        void operator()() const {
            std::cout << "action!\n";
        }
    };
     
    int main() {
        Foo foo;
        std::thread thread{foo};
        thread.join();
    }
    Je pense que ça devrait t'aider

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    Le gros problème, avec les "fonctions membres" -- ou les "méthodes"(*) -- c'est que le compilateur va automatiquement faire "quelque chose" pour permettre à la fonction de savoir à partir de quelle instance de la classe la fonction a été appelée.

    En effet, une fonction "libre" ne va nécessiter que les paramètres dont la liste est fournie. Ainsi, si tu as une fonction libre qui prend la forme de
    il n'y a -- vraiment -- que trois paramètres qui sont requis pour pouvoir faire appel à cette fonction.

    Par contre, si on envisage une fonction équivalente qui serait une fonction membre d'une classe quelconque, par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MaClasse{
    public:
        void bar(int, float); // le nom est différent, mais la signature est "sensiblement" la même n'est-ce pas?
        /* ... */
    };
    Nous avons affaire à une fonction dont l'exécution dépend expressément d'une instance bien particulière de MaClasse.

    En effet, on peut "décemment" estimer que la classe MaClasse va également contenir "un certain nombre" de données "internes", qui seront susceptibles de varier d'une instance à l'autre de cette classe. Il faut donc pouvoir ... récupérer au niveau de la fonction les données qui dépendent de l'instance particulière de MaClasse à partir de laquelle la fonction a été appelée.

    Or, une fois que le code a été traduit en langage machine, il n'y a absolument aucune différence dans la manière dont sont traitées les fonctions libres et les fonctions membres.

    Par exemple, quand bien même nous aurions des dizaines, voire des centaines d'instances de MaClasse, la fonction bar n'existerait qu'en un seul et unique exemplaire ( du moins, si elle n'est pas déclarée inline) et serait appelée exactement de la même manière que la fonction foo, à savoir:
    1. on garde l'adresse mémoire de l'instruction qui suit l'appel "en mémoire"
    2. on prend les paramètres transmis lors de l'appel de la fonction en charge
    3. on saute à l'adresse mémoire à laquelle les instructions spécifiques à la fonction se trouvent
    4. une fois l'exécution de la fonction terminée, on reprend l'adresse de l'instruction qui suit l'appel pour continuer le travail

    (bon, c'est simplifié, mais le principe est bel et bien correct )

    La grosse différence qu'il va donc y avoir entre une fonction libre et une fonction membre va donc tenir dans le faite que le compilateur va automatiquement ajouter un paramètre -- un pointeur sur MaClasse qu'il appellera this -- comme premier paramètre de la fonction membre, et ce, sans même nous demander notre avis.

    La fonction membre pourrait donc parfaitement être représentée sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void bar(MaClasse * this, int, float)
    et, peut-être, commences tu dés lors à comprendre où le problème risque de se situer

    BINGO! Le fait est que, si j'ai deux classes différentes qui exposent toutes les deux une fonction portant le même nom, nécessitant les mêmes paramètres, et renvoyant le même type de valeur (ou ne renvoyant rien, dans le cas présent) sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class MaClasse{
    public:
        void bar(int, float);
        /* ... */
    };
    class AutreClasse{
    public:
        void bar(int, float);
        /* ... */
    };
    /* et l'utilisation */
    int main(){
        MaClasse c;
        c.bar(10, 3.1415926); 
        AutreClasse a;
        a.bar(10, 3.1415926); 
    }
    Hé bien, la seule chose qui va changer entre les deux fonctions, ce sera ... le type de la donnée pointée par this: Ce sera une donnée de type MaClasse pour la première, et une donnée de type AutreClasse pour la deuxième.

    Et il va de soi qu'il est totalement impensable de se retrouver dans une situation dans laquelle ce serait la "version" de bar issue de MaClasse qui serait appelée alors que nous avons fait appel à bar à partir d'une instance de AutreClasse

    C'est donc là que le gros problème va apparaitre: Pour pouvoir transmettre la fonction membre d'une classe à une autre fonction, il faut impérativement également transmettre ... un pointeur sur l'instance à partir de laquelle la fonction devra être appelée.

    Ou bien il faut que la fonction qui sera appelée ne dépende d'aucune instance particulière de la classe (il faut donc que ce soit une fonction membre statique).

    Enfin, ** l'idéal ** serait sans doute d'utiliser la classe std::function pour créer tes callbacks, car cette classe offre pas mal de possibilités

    Nous pourrions par exemple envisager d'avoir un code (complet) qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <iostream>
    #include <functional>
    class MaClasse{
    public:
        MaClasse(int id):id{id}{
        }
        void bar(int i, float f) const{
            std::cout<<"bar called from "<<id
                     <<" with parameters \n"
                     <<i<<" as integer\n"
                     <<"and "<<f<<" as float\n";
        }    
        void truc(int i, float f) const{
            std::cout<<"truc called from "<<id
                     <<" with parameters \n"
                     <<i<<" as integer\n"
                     <<"and "<<f<<" as float\n";
     
        }
    private:
        int id;    
    };
    using callback = std::function<void(MaClasse*, int, float)>;
    void foo(MaClasse * ptr, callback c, int i, float f){
        c(ptr, i, f);
    }
    int main(){
        MaClasse c{3};
        foo(&c,MaClasse::bar,10, 3.141592);
        foo(&c,MaClasse::truc,10, 3.141592);
        return 0;
    }
    ou, si les fonctions auxquelles tu souhaite faire appel ne dépendent d'aucune instance particulière de la classe à partir de laquelle elles sont appelée, tu pourrais aussi envisager un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <iostream>
    #include <functional>
    class MathComputations{
    public:
        static int add(int a, int b){
            return a + b;
        }
        static int multiply(int a, int b){
            return a * b;
        }
    };
     
    using callback = std::function<int ( int, int )>;
    int foo( callback c, int a, int b){
        return  c(a, b);
    }
    int main(){
        std::cout<<" 3 + 4 = "<<foo(MathComputations::add, 3,4);
        std::cout<<"\n";
        std::cout<<" 3 * 4 = "<<foo(MathComputations::multiply, 3,4);
        return 0;
    }
    (note que, dans les deux cas, j'ai préféré utiliser un alias de type pour le callback, je trouve cela plus "facile" )

    (*)Le fait est que le terme "méthode" pêche quelque part (en tout cas en C++) par sa spécificité alors qu'il est présenté dans un contexte dans lequel il est ** censé ** être le plus générique possible Mais, laisse moi t'expliquer cette phrase

    Dans la plupart des langages orientés objets, une fonction qui appartient à une classe n'a que deux possibilités:
    • Soit, c'est une fonction qui ne dépend d'aucune instance particulière de la classe dans laquelle elle se trouve ( disons "fonction statique", par facilité)
    • Soit, c'est une fonction dont le comportement peut automatiquement être redéfini dans les classes dérivées (nous pourrions la qualifier de "virtuelle")

    Par exemple, en java, tu pourrais trouver une hiérarchie de classes proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Base{
        public void afficher(){
            system.printnl("ceci est une base");
        }
    };
    public class Derived inherits Base{
        public void afficher(){
            system.printnl("ceci est une derivee");
        }
    }
    Et cette possibilité de redéfinir le comportement dans la classe dérivée est systématique pour l'ensemble de toutes les fonctions (non statiques) exposées par la classe de base.

    Ces deux catégories (fonctions "statiques" Vs fonction "virutelles") suffisent amplement pour la plupart des langages, car si la fonction dépend d'une instance bien particulière de la classe, on s'attend effectivement à ce que son comportement soit susceptible d'être adapté en fonction du type réel de l'instance à partir de laquelle la fonction sera appelée (c'est ce que l'on appelle le polymorphisme d'inclusion)

    Seulement, voilà, les choses sont "un peu plus complexes" en C++. Car, par défaut, le comportement d'une fonction membre n'est pas susceptible d'être redéfini dans les classes. Pour que le comportement d'une fonction membre soit susceptible d'être redéfini dans la classe dérivée, il faut impérativement déclarer cette fonction comme virtuelle au niveau de la classe de base (et ** idéalement ** déclarer son comportement comme "redéfini" dans les classes dérivées qui redéfinissent le comportement).

    Nous avons donc trois possibilités distinctes en C++:
    • les fonctions membres "statiques", indépendante de toute instance particulière de la classe
    • les fonctions membres "non statiques" et "non virtuelles", dont le comportement n'est pas susceptible d'être redéfini dans les classes dérivées
    • les fonctions membres "non statiques" et "virtuelles", dont le comportement est susceptible d'être redéfini dans les classes dérivées.

    Mais, du coup, même si l'on ne tient pas compte des fonctions membres statiques (dont l'exécution ne dépend d'aucune instance particulière de la classe) la notion de "méthode" telle qu'elle est présentée de manière générale dans les ouvrages destinés à la conception ne correspond qu'à une partie seulement des possibilités qui sont offertes par le langage.

    Pire encore, cette notion correspond en définitive à l'exception du langage, vu que ce que permet cette notion n'a absolument rien "d'automatique", et doit au contraire être demandé explicitement.

    C'est la raison pour laquelle nous parlerons beaucoup plus souvent de "fonction membre" (statique ou non statique, éventuellement virtuelle) qye de méthode en C++

  14. #14
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut
    Messieurs (Dames, qui sait),

    merci à vous tous pour vos interventions que j'ai lues attentivement. Je rajoute la réponse qui m'a semblé la plus simple à ma question (question fort basique, au demeurant).

    Initialement j'avais quelque-chose comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     void test(int a)
    {
       cout << "entier :" << a << endl;
    }
     
    void function1(void (*function)(int))
    {
       function(1);
    }
     
    int main()
    {
       function1(&test);
    }
    Qui peut se réécrire en objet:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class aClass
    {
    public:
       void aTest(int a)
      {
          cout << "entier :" << a << endl;
       }
    };
     
    void function2(void (aClass::*function)(int), aClass& a)
    {
       (a.*function)(1);
    }
     
    int main()
    {
       aClass a;
       function2(&aClass::aTest, a); 
    }

  15. #15
    Membre éprouvé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2016
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2016
    Messages : 278
    Points : 946
    Points
    946
    Par défaut
    Dans la plupart des langages orientés objets, une fonction qui appartient à une classe n'a que deux possibilités:
    Soit, c'est une fonction qui ne dépend d'aucune instance particulière de la classe dans laquelle elle se trouve ( disons "fonction statique", par facilité)
    Soit, c'est une fonction dont le comportement peut automatiquement être redéfini dans les classes dérivées (nous pourrions la qualifier de "virtuelle")
    Ben... non... Une méthode/fonction membre peut être "private" en java, et aucune autre classe ne pourra en hériter. Ou alors je n'ai pas bien compris.

    De plus, le terme de méthodes est bien parfois utilisé en C++. J'ai bien compris que ce n'était pas l'usage le plus courant, mais ce n'est pas inexistant non plus:
    Tutorial C++ : Définition des méthodes
    http://william.arrouy.free.fr/cpp/cpp3.html
    Une classe va permettre de regrouper en une seule entité des données membres et des fonctions membres appelées méthodes.
    https://www.fresnel.fr/perso/stout/l...es_Classes.pdf
    Les traitements attachés à une classe sont appelés méthodes (ou fonctions membres, opérations).
    https://www.labri.fr/perso/bourqui/d...2B-classes.pdf

  16. #16
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Ben... non... Une méthode/fonction membre peut être "private" en java, et aucune autre classe ne pourra en hériter. Ou alors je n'ai pas bien compris.

    De plus, le terme de méthodes est bien parfois utilisé en C++. J'ai bien compris que ce n'était pas l'usage le plus courant, mais ce n'est pas inexistant non plus:
    Mais on s'en fout en fait de l'accessibilité!

    Car tout -- une donnée, un fonction ou même un type de donnée, s'il est imbriqué dans une autre classe-- peut être public ou privé.

    L'accessibilité n'est qu'une convention que l'on met en place entre l'homme et le compilateur (ou l'interpréteur) pour signaler que l'accès à "quelque chose" est "plus ou moins limité", parce que l'on peut faire confiance au compilateur (ou à l'interpréteur) pour être "plus buté" que nous, et que, si on lui dit que "on ne peut accéder à telle chose qu'à partir des fonctions qui font partie de a classe", on peut être sur qu'il nous engueulera si on essaye d'accéder à la chose en question à partir de "l'extérieur" de la classe.

    Mais, une fois le code binaire exécutable généré pour que le processeur puisse le prendre en charge, la notion d'accessibilité n'est plus représentée nulle part, et une fonction, une donnée, ou même un type de donnée ne seront pas représentés différemment dans le code binaire exécutable s'ils ont été marqués privés que s'ils ont été définis comme publics.

    Par contre, ce qui va effectivement changer pas mal de choses, c'est de savoir si "quelque chose" -- qu'il s'agisse encore une fois d'une donnée, d'une fonction ou même d'un type de donnée -- qui est fourni comme "faisant partie d'une classe" dépend effectivement d'une instance bien particulière de la classe ou non.

    Parce que, si "quelque chose" dépend d'une instance particulière de la classe, ben, nous n'aurons pas d'autre choix que de fournir l'instance dont il dépend pour pouvoir y accéder alors que, si ce "quelque chose" ne dépend d'aucune instance particulière, ben, on peut y accéder sans même avoir pris la peine de créer la moindre instance de la classe.

    Attention, je ne dis pas que la notion d'accessibilité est inutile. Je dis juste qu'elle n'est pas indispensable. Je dis juste que l'accessibilité et le principe sous-jacent à cette notion qu'est l'encapsulation
    1. n'est pas le principe essentiel de la programmation orientée objet, car le vrai principe fondateur de cette approche est la substituabilité au sens du principe de substitution de Liskov (LSP)
    2. est souvent mal comprise, car les gens finissent trop souvent persuadé qu'il "suffit" de placer une donnée dans l'accessibilité privée et d'ajouter un accesseur (getter), ce qui fait parfois sens, et un mutateur (setter) pour que la donnée soit correctement encapsulée, ce qui est totalement faux (*)
    3. est parfaitement possible et mise en oeuvre y compris dans les langages purement impératifs comme le C. Qu'il te suffise de penser à la structure FILE, à laquelle on n'a accès qu'au travers d'un nombre réduit et clairement défini de fonctions qui effectuent des tâches clairement définies
    (*)En cherchant bien, je devrais pouvoir te retrouver l'une ou l'autre de mes interventions qui expliquent ce point. Je ne vais juste pas alourdir ma réponse aujourd'hui, tout en restant à ta disposition si tu veux des explications supplémentaires

  17. #17
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 128
    Points : 33 052
    Points
    33 052
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par Chezkele Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    obj.fctMembre(&fct, &err);
    avec fct est est une fonction, et je voudrais savoir si je peux remplacer cette fonction par une fonction membre.
    Ouf, enfin un semblant de code dis donc...
    Tout ceci est faisable avec std::function, ou une méthode template qui prend un callable et une lambda.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void fctMembre(std::function<void(int)> fct) { fct(1); }
    template<class Fct>
    void fctMembre(Fct fct) { fct(1); }
    C'est beaucoup plus simple, clair et flexible et ça permet de l'utiliser avec ce qu'on veut.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class aClass
    {
    public:
       void aTest(int a)
      {
          cout << "entier :" << a << endl;
       }
    };
     
    void function2(std::function<void(int)> fct)
    {
       fct(1);
    }
     
    template<class Fct>
    void function2(Fct fct)
    {
       fct(1);
    }
     
    void whatever(int i) {std::cout << i << std::endl; }
     
    int main()
    {
       aClass a;
       function2([&a](int i) { a.aTest(i); });
       function3([&a](int i) { a.aTest(i); });
       function2(whatever);
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 28/01/2011, 16h37
  2. Réponses: 2
    Dernier message: 30/03/2009, 12h21
  3. Réponses: 11
    Dernier message: 21/05/2006, 14h39
  4. transmettre une valeur par l'url
    Par Destampy dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 07/06/2005, 15h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo