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 :

Limiter la redéfinition d'une fonction virtuelle ?


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 11
    Points : 8
    Points
    8
    Par défaut Limiter la redéfinition d'une fonction virtuelle ?
    Bonjour !
    Voila, j'aimerais savoir s'il est possible d'implémenter une fonction abstraite =0 en de façon qu'une classe dérivée ne puisse pas l'overrider.

    Plus précisément, voici une Interface, et une classe A implémentant sa fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Interface
    {
    public:
            virtual void Foo() = 0;
    };

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class Abstraite
    {
    public:
            void Foo() 
            { 
                    // Do things...
                    Bar();
            }
     
            /** Cette fonction la est à implémenter par la classe dérivée **/
            virtual void Bar() = 0;
    };
    Maintenant supposons qu'une classe Concrete redéfinisse Foo()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Concrete
    {
    public:
            void Foo() 
            { 
                // Do other things...
            }
     
            void Bar() {}
    };
    Je me demande s'il est possible de se débrouiller pour que, quand j'appelle Foo() sur un pointeur de mon Interface, ce soit Abstraite::Foo() qui soit appelée et pas Concrete::Foo().
    Autrement dit, qu'il soit impossible pour une classe dérivée de Abstraite d'overrider Foo(), malgré qu'elle soit virtuelle.

    Merci d'avance

  2. #2
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Ce que tu demandes n'a aucun sens.

    Tu voudrais que ta fonction soit virtuelle (appelle de la fonction membre de la classe dérivée), et qu'elle ne le soit pas vraiment en fait (appelle de la fonction membre de la classe mère si on réfère celle-ci).

    Quel utilité ?

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

    Informations professionnelles :
    Activité : aucun

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

    Peut etre la solution que tu cherche passe-t-elle par ce que l'on appelle le patterne "NVI" (non virtual interface, ou interface virtuelle)...

    Cela te donnerait quelque chose 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
    23
    24
    25
    26
    27
    28
    29
    30
    class Interface
    {
        public:
            // une fonction non virtuelle
            void foo() 
            {
                bar();
            }
        private:
            /* une fonction virtuelle pure, qui doit être réimplémentée
             * pour les classes instanciables
             */
            virtual void bar() = 0;
     
    };
    class Abstract : public Interface
    {
        public:
           Abstract(/* parametres éventuels */ );
           /* pour que la classe reste abstraite */
           virtual ~Abstract() = 0;
        private:
          /* mais ici, nous avons assez d'infos pour définir la fonction bar */
          virtual void bar();
    }
    /* dans le cpp */
    void Abstract::bar()
    {
        /* ce qui doit être fait */
    }
    De cette manière, nous ne serons jamais tenté de redéfinir foo, vu que ce n'est pas une fonction virtuelle.

    Par contre, rien n'empêche l'utilisateur de redéfinir bar dans une classe dérivée de Abstract si, d'aventure, le comportement défini dans Abstract ne lui convient pas.

    Disons qu'il ne sera pas forcément tenté de le faire pour toutes les classes, étant donné que le compilateur ne se plaindra absolument pas s'il ne le fait pas (Abstract est une classe abstraite du fait de sont destructeur virtuel pur, et non du fait de la déclaration de bar, étant donné que bar ne l'est plus).

    Ceci dit, même si tu estimes, actuellement, que le comportement que tu va définir pour bar dans Abstract est amplement suffisant, j'aurais tendance à estimer que c'est une erreur que de vouloir empêcher toute classe dérivée de Abstract de le redéfinir.

    D'abord, parce que les besoins évoluent sans cesse, et que, "quelqu'un" (peut être toi) peut vouloir que bar "en fasse un peu plus" (ou le fasse différemment) pour une classe particulière, ensuite parce que, si le "quelqu'un" en question est tout à fait externe à l'équipe de développement, parce qu'il est peut être prétentieux d'estimer savoir mieux que l'utilisateur ce qui est bon pour lui

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    J'avais voulu simplifier les données du problème mais je me rend compte que j'en ai trop enlevé.

    Je n'ai pas le choix de rentre l'Interface non virtuelle, car il s'agit d'une interface "Observer", sans implémentation aucune donc.

    Ma classe Abstraite en revanche implémente partiellement (dans un but unique de réutilisation de code) un fonctionnement qui sera commun à toute une catégorie d'observateurs, mais pas à tous, puis passe le relai à la fonction Bar virtuelle pour implémentation plus bas dans la hiérarchie.

    Du coup, étant donné qu'une classe qui héritera de celle-ci le fera uniquement dans l'optique de partager une implémentation, je vois pas trop l'interêt que quiconque pourrait avoir à modifier cette implémentation elle même. Autant créer une autre implémentation de l'Interface. Pour moi ça revient à acheter un paquet de pain de mie et à enlever toute la mie pour garder que la croûte...

    M'enfin, plus j'y réfléchis et plus je me dit que ce n'est pas si dérangeant que ça...
    Mais ça me semblait étrange qu'on ne puisse pas avoir ce genre de contrôle sur le polymorphisme.

    Quoi qu'il en soit merci pour l'aide (Tu m'avais déja bien aidé pour une autre question ou j'ai jamais eu le temps de répondre parce que le temps de tester le truc j'avais plus internet http://www.developpez.net/forums/d80...encapsulation/)

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    Ce que tu demandes n'a aucun sens.

    Tu voudrais que ta fonction soit virtuelle (appelle de la fonction membre de la classe dérivée), et qu'elle ne le soit pas vraiment en fait (appelle de la fonction membre de la classe mère si on réfère celle-ci).

    Quel utilité ?
    Non pas vraiment.
    Je voudrais que ma fonction soit vraiment virtuelle (appel de la fonction de la classe dérivée depuis un pointeur base), mais qu'une classe l'implémentant puisse décider que le polymorphisme descendant depuis la classe mère s'arrête à elle (appel de la fonction de dérivée1 depuis un pointeur base, même si dérivée2 plus bas dans la hiérarchie la surcharge)

  6. #6
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par N0vember Voir le message
    Non pas vraiment.
    Je voudrais que ma fonction soit vraiment virtuelle (appel de la fonction de la classe dérivée depuis un pointeur base), mais qu'une classe l'implémentant puisse décider que le polymorphisme descendant depuis la classe mère s'arrête à elle (appel de la fonction de dérivée1 depuis un pointeur base, même si dérivée2 plus bas dans la hiérarchie la surcharge)
    Ce n'est pas possible car une nouvelle fonction dans la classe intermédiaire avec la même signature que la fonction virtuelle sera virtuelle même si elle ne met pas le mot-clé 'virtual'. Qui plus est, la visibilité de la fonction ou de l'héritage (public, protégé, virtuel) n'a pas d'impact sur la résolution dynamique de l'appel d'une fonction virtuel. La seule possibilité est d'utiliser le pattern NVI et de faire ce qui doit l'être dans la partie non virtuelle ou d'utiliser une approche générique (template)

Discussions similaires

  1. Réponses: 14
    Dernier message: 18/07/2011, 21h00
  2. Une fonction virtuelle ne peut pas retourner un template!
    Par coyotte507 dans le forum Langage
    Réponses: 10
    Dernier message: 08/02/2008, 20h39
  3. Interdire la redéfinition d'une fonction
    Par mister3957 dans le forum C++
    Réponses: 6
    Dernier message: 01/03/2007, 15h27
  4. Réponses: 7
    Dernier message: 05/05/2006, 09h48
  5. Réponses: 2
    Dernier message: 05/03/2006, 19h29

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