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

Langage C++ Discussion :

appel d'une fonction surchargée


Sujet :

Langage C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut appel d'une fonction surchargée
    Bonsoir,

    J'ai une question qui peut paraître idiote, peut-on écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class Base
    {
        public :
            virtual void f(){};
    }
     
    class Derived : public Base
    {
        public :
            void f(){ Base::f(); };
    }
    Dis comme çà, c'est un peu inutile. Le but est en fait d'utiliser f() tel que définit dans Base en ajoutant des fonctionnalités pour Derived.

    Merci d'avance.

  2. #2
    Membre très actif
    Homme Profil pro
    En rupture avec la societé
    Inscrit en
    Novembre 2008
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : En rupture avec la societé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 144
    Par défaut
    salut

    dans un premier temps tu ne surcharge pas une méthode mais tu la redéfinis
    La surcharge correspond a déclarer et définir plusieurs fonctions ayant le même nom, à condition que les listes de leurs arguments diffèrent

    avec la redéfinition de la méthode dans ta class dérivé, tu masque celle de la class de base.
    l'utilisation de virtual fonctionne dans le cadre du polymorphisme.

    et oui effectivement tu peux appeler la méthode de la class de base dans la méthode redéfini de la class dérivé.

    Rien ne t'empêche non plus d'appelé la méthode de la class de basse malgré la redéfinition.
    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
     
    class Base
    {
        public :
            virtual void f(){};
    }
     
    class Derived : public Base
    {
        public :
            void f(){ Base::f(); };
    }
     
    Derived maClass;
    maClass.Base::f();
    a plus

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut
    C'est vrai, ce n'est qu'une redéfinition. Shame on me !

    Mais avec le code suivant, c'est une surcharge, non ?

    Pour mieux comprendre le but :

    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
     
    class Base
    {
        public :          // en "protected :" ça paraît plus compliqué !
            int i;
     
        public :
            virtual void f(){};
    }
     
    class Derived : public Base
    {
        public :
            void f(const int val);
    }
     
    void Derived::f(const int val)
    {
        Base::f();
        i = val;
    }
    Je peux donc écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Derived maClass;
    Base* instanceDerived = &maClass;
     
    instanceDerived->f(0);

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par titibete Voir le message
    C'est vrai, ce n'est qu'une redéfinition. Shame on me !

    Mais avec le code suivant, c'est une surcharge, non ?

    Pour mieux comprendre le but :

    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
     
    class Base
    {
        protected :
            int i;
     
        public :
            virtual void f(){};
    }
     
    class Derived : public Base
    {
        public :
            void f(const int val);
    }
     
    void Derived::f(const int val)
    {
        Base::f();
        i = val;
    }
    Là, tu as, effectivement, une surcharge...

    Mais attention, ce n'est pas une redéfinition, ce qui fait que si tu écrivait purement et simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Derived::f(const int val)
    {
        f();
        i = val;
    }
    sans avoir redéfini void f() dans ta classe dérivée, cela reviendrait exactement au même (car f() est une fonction qui est tout à fait accessible depuis Derived, vu qu'elle fait partie de l'interface publique de Base )
    par contre,
    Je peux donc écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Derived maClass;
    Base* instanceDerived = &maClass;
     
    instanceDerived->f(0);
    Hééé non...

    La raison est simple: ton pointeur instanceDerived passe pour être... du type Base, et non du type Derived.

    Tu ne peux donc invoquer que les fonctions publiques qui font partie de ... l'interface (publique) de Base.

    Or, en tant que Base, la seule fonction qui soit connue, c'est celle... ne prenant aucun argument

    D'ailleurs, si tu avais essayé de compiler, tu t'en serais aperçu, car il t'aurais "jeté" à coup de "fonction f(int) non déclarée dans Base" (ou message similaire )

    Au final: avec tes classes Base et Derived telles que tu les as présentées, tu en arrive aux situations suivantes:
    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
    int main()
    {
        Derived deriv;
     
        deriv.f(); // appelle Base::f(), car elle n'a pas été redéfinie pour Derived
     
        deriv.f(5); // appelle Derived::f(int)
     
        Base & b=deriv; // ca marche aussi avec les références :D
     
        b.f(); // OK : b passe pour être du type Base
     
        b.f(10); // KO : b passe pour être du type Base qui ne déclare pas
                 // de fonction f(int)
     
        return 0;
    }
    EDIT: Il faut noter que, si une fonction est déclarée virtuelle dans la classe de base et redéfinie dans la classe dérivée sans avoir été déclarée virtuelle, la redéfinition dans la classe dérivée sera néanmoins réputée virtuelle.

    Si tu invoque la fonction redéfinie au départ d'un objet dont le type réel est la classe dérivée mais passant pour être du type de la classe de base, tu observera effectivement le comportement polymorphe, car ce sera bel et bien la version de la classe dérivée qui sera utilisée.

    Par contre, si la fonction n'est pas déclarée virtuelle dans la classe de base, et qu'elle est redéfinie dans la classe dérivée, la redéfinition cachera simplement l'implémentation de la classe de base.

    Cela signifie que, si tu invoque la fonction depuis un objet du type de la classe dérivée, ce sera la version de la classe dérivée qui sera utilisée, mais que si tu invoque la fonction depuis un objet dont le type réel est la classe dérivée mais passant pour être un objet du type de la classe de base (référence ou pointeur), ce sera... la version de la classe de base qui sera utilisée, et tu n'observera donc pas le comportement polymorphe
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut
    Donc, pour que ça marche, il faudrait que je code :

    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
     
    class Base
    {
        public :         
            int i;
     
            virtual void f(){};
            virtual void f(const int val){};
    }
     
    class Derived : public Base
    {
        public :
            void f(const int val);
    }
     
    void Derived::f(const int val)
    {
        f();
        i = val;
    }
    C'est çà ?

  6. #6
    Membre très actif
    Homme Profil pro
    En rupture avec la societé
    Inscrit en
    Novembre 2008
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : En rupture avec la societé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 144
    Par défaut
    Citation Envoyé par titibete Voir le message
    Donc, pour que ça marche, il faudrait que je code :

    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
     
    class Base
    {
        public :         
            int i;
     
            virtual void f(){};
            virtual void f(const int val){};
    }
     
    class Derived : public Base
    {
        public :
            void f(const int val);
    }
     
    void Derived::f(const int val)
    {
        f();
        i = val;
    }
    C'est çà ?
    tu as exactement la même chose avec en plus la redéfinition de la surcharge f(const int val) et tu masque toujours f() et ces surcharges en base.

    Que cherche tu vraiment a faire avec cette exemple.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut
    Ce que je cherche à faire, c'est ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Derived maClass;
    Base* instanceDerived = &maClass;
     
    instanceDerived->f(0);

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    A peu près, si ce n'est que, dans le cas présent, Base::f (sans argument) n'a pas vraiment d'intérêt à être déclarée virtuelle, vu qu'elle n'est pas redéfinie...

    Il faut comprendre que la virtualité a un cout, entre autre, du fait du passage par une table des fonctions virtuelles (la vtable) qui permet, justement, de déterminer quelle fonction appeler effectivement.

    L'idée est donc de ne déclarer virtuelles que les fonctions qui ont de bonnes raisons de l'être

    Maintenant, nous sommes d'accords sur le fait que je ne fais que répondre à la question "pour que cela marche"...

    A coté de cela, je ne me prononce absolument pas sur l'opportunité de faire apparaitre f() ou f(int) dans l'interface de la classe de base... Et encore moins sur l'opportunité de permettre de les redéfinir dans les classes dérivées.

    Pour pouvoir se prononcer sur ces opportunité, il faudrait présenter un cas concrêt, avec des classes dont les responsabilités seraient connues et donc dont les services attendus tant par f() que par f(int) seraient clairement identifiés
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut
    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
     
    class Base
    {
        public :         
            void f(){};
            virtual void f(const int val);
    }
     
    class Derived : public Base
    {
        private :
            int i;
     
        public :
            void f(const int val);
    }
     
    void Derived::f(const int val)
    {
        f();
        i = val;
    }
     
    Base* instanceDerived = new Derived();
     
    instanceDerived->f(0);
    Ca ne marche pas, puisque i n'est pas connu dans Base, si ?

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par titibete Voir le message
    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
     
    class Base
    {
        public :         
            void f(){};
            virtual void f(const int val);
    }
     
    class Derived : public Base
    {
        private :
            int i;
     
        public :
            void f(const int val);
    }
     
    void Derived::f(const int val)
    {
        f();
        i = val;
    }
     
    Base* instanceDerived = new Derived();
     
    instanceDerived->f(0);
    Ca ne marche pas, puisque i n'est pas connu dans Base, si ?
    Si ça marche...

    Il faut comprendre que tu rentre dans une logique de polymorphisme, et que tu as donc affaire à deux types distincts:

    Le type statique de l'objet d'un côté, qui est vu par le compilateur au moment de la compilation.

    Ce qui importe pour ce type, c'est que le compilateur sache qu'il dispose de la fonction que l'on essaye d'appeler ( f(int) ).

    Comme cette fonction fait bel et bien partie de l'interface de Base, il n'y a pas de problème, le compilateur n'ira pas voir plus loin

    De l'autre, il y a le type dynamique de l'objet, celui qui sera réellement utilisé lors de l'exécution.

    Comme le type dynamique de l'objet est Derived, la "version" de f(int) qui sera réellement exécutée est celle de Derived.

    Et, comme la classe Derived dispose de i, il n'y aura pas de problème

    La seule chose à laquelle il faille faire attention, c'est à ce que l'on prévoit pour f(int) au niveau de Base.

    Soit on est en mesure de déterminer un comportement cohérent (du point de vue de Base) pour cette fonction, en veillant cependant à n'utiliser que les membres et fonctions membres de Base, et l'on peut donc l'implémenter.

    Soit, on n'est pas en mesure de déterminer le comportement cohérent, sans doute parce que l'on ne dispose pas des membres et des fonctions qui nous permettraient de fournir ce comportement.

    Tu dois donc préciser au compilateur qu'il ne doit pas en chercher l'implémentation en déclarant la fonction virtuelle pure.

    Cela aura cependant comme résultat de rendre la classe Base abstraite, c'est à dire que tu ne pourra pas créer d'objet de type Base (mais rien ne t'empêchera cependant de faire passer un objet de type Derived comme étant de type Base ) ni de n'importe quelle classe dérivée pour laquelle tu ne fournirais pas l'implémentation de f(int).
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Mais attention, ce n'est pas une redéfinition, ce qui fait que si tu écrivait purement et simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Derived::f(const int val)
    {
        f();
        i = val;
    }
    sans avoir redéfini void f() dans ta classe dérivée, cela reviendrait exactement au même (car f() est une fonction qui est tout à fait accessible depuis Derived, vu qu'elle fait partie de l'interface publique de Base )
    Si ma mémoire ne me joue pas des tours (et u test vite fait tend à le confirmer), non f() ne suffit pas (il faut bel et bien préciser Base::f()) car f() est masqué par f(int) lors du name lookup.

  12. #12
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par gl Voir le message
    Si ma mémoire ne me joue pas des tours (et u test vite fait tend à le confirmer), non f() ne suffit pas (il faut bel et bien préciser Base::f()) car f() est masqué par f(int) lors du name lookup.
    Ah, oui, au temps pour moi...

    j'ai parlé un peu vite
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut
    Citation Envoyé par gl Voir le message
    il faut bel et bien préciser Base::f().
    Je note.


    Citation Envoyé par titibete Voir le message
    Ca ne marche pas, puisque i n'est pas connu dans Base, si ?
    Oui, je me suis un peu embrouillé, j'écrivais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    vector<Base*> vBase;
    Derived* instanceDerived = new Derived();
     
    vBase.push_back(instanceDerived);
    au lieu de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    vector<Base*> vBase;
    Base* instanceDerived = new Derived();
     
    vBase.push_back(instanceDerived);

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Je ne suis pas sur d'avoir vraiment compris l'objectif de tout ça. Mais j'ai l'impression que tu donnes à f 2 rôles différents : le comportement préliminaire et l'interface. Pourquoi ne pas séparer ces deux rôles :
    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
    class Base
    {
    public :
        void f(const int param_)
        {
               pre_f();
               do_f(param_);
        }
    private:
        void pre_f();
        {
                 // ton ancien Base::f();
        }
        virtual void do_f(const int param_)=0;
    };
     
    class Derive : public Base
    {
    private :
       int val;
       virtual void do_f(const int param_)
        {
              val = param_;
         }
     
    };
    Sinon, pour les fonctions virtuelles cf ce tuto

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 36
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Mais j'ai l'impression que tu donnes à f 2 rôles différents : le comportement préliminaire et l'interface. Pourquoi ne pas séparer ces deux rôles
    C'est vrai, et c'est la structure que j'ai finalement adoptée (c'est une chose que j'avais déjà vue dans la faq ), en dehors du virtuel pur de do_f() puisque j'ai besoin d'instancier la classe de base.

    Pourrais-tu m'éclairer sur l'utilité de pre_f() plutôt que de tout définir dans f() ?

  16. #16
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par titibete Voir le message
    Pourrais-tu m'éclairer sur l'utilité de pre_f() plutôt que de tout définir dans f() ?
    Lisibilité du code. Séparation des rôles.

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

Discussions similaires

  1. appel d'une fonction à partir d'un popup
    Par villeneuvejsp dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 02/12/2004, 17h00
  2. Appel d'une fonction
    Par georgeabitbol dans le forum ASP
    Réponses: 4
    Dernier message: 08/07/2004, 14h29
  3. Réponses: 4
    Dernier message: 02/06/2004, 16h35
  4. Appel d'une fonction
    Par jfphan dans le forum ASP
    Réponses: 4
    Dernier message: 14/04/2004, 15h06
  5. A la recherche de l'appel d'une fonction...
    Par karl3i dans le forum C
    Réponses: 3
    Dernier message: 24/09/2003, 12h34

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