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 :

[POO] Accéder à une méthode statique à partir d'une instance


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut [POO] Accéder à une méthode statique à partir d'une instance
    |Edit:
    |Le titre du post pourrait plutôt être "Quand utiliser le Singleton ?" à
    |partir du post #5.

    Bonjour à tous ;-)

    Voici mon problème: j'ai une variable _vDrawer qui a comme type un pointeur vers une classe abstraite VDrawer. _vDrawer peut alors pointer soit vers VDrawer2d, soit vers VDrawer3d.
    VDrawer2d et VDrawer3d héritent aussi d'une classe Singletonqui contient une méthode statique kill(), à laquelle j'aimerais pouvoir accéder à partir de _vDrawer.

    Voici mon code actuel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    VEngine::getInstance()->getVideoDrawer()::kill();
    getVideoDrawer() retourne évidement _vDrawer.
    Evidement, le ::kill() ne fonctionne pas comme il devrait ;-)

    Il faut aussi ajouter que le VDrawer n'hérite pas de Singleton, tandis que VDrawer2d et VDrawer3d le font. C'est peut-être la cause du problème.

    Merci d'avance !

    Edit: J'ai essayé ceci aussi, mais il semblerait que typeid ne serve qu'à comparer 2 classes différentes.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typeid(*(VEngine::getInstance()->getVideoDrawer()))::kill();
    Edit2: On pourrait aussi faire hériter VDrawer de Singleton pour ne pas avoir d'héritage multiple, mais, vous vous en doutez, VDrawer est un Builder et le faire hériter de la classe Singleton l'obligerait à devenir une classe template pour permettre aux classes VDrawer2d et VDrawer3d de devenir des singletons aussi.
    Jusque là, c'est faisable sans trop de problèmes, mais ça détruit tout l'intéret du builder puisque je serais obligé de déclaré _vDrawer comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    VDrawer<VDrawer2d> *_vDrawer;
    Edit3: Solution temporaire trouvée: créer une méthode non-static kill dans VDrawer. Elle serait définie de cette manière dans VDrawer2d par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void VDrawer2D::kill() {
    	VDrawer2D::kill();
    }
    Malgré ça, je n'aime pas avoir ce genre de bidouille dans mon code s'il y a moyen de l'éviter. J'ai cependant bien peur que ce ne soit possible dans mon cas.

  2. #2
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Je voudrais être sûr de comprendre : VEngine::getInstance() renvoie un singleton de VEngine, et dessus getVideoDrawer() renvoie un singleton de VDrawer ? Dans ce cas, je pense que la syntaxe serait plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    VEngine::getInstance()->getVideoDrawer()->kill();
    si getVideoDrawer renvoie un pointeur, ou avec un '.' s'il renvoie une référence ; mais c'est peut-être encore plus simple comme ça :

    si VDrawer est bien un singleton.

    Ceci-dit, si VDrawer n'hérite pas de Singleton, et qu'il ne déclare pas une méthode kill(), je pense pas que ça puisse marcher aussi facilement ; il te faudra probablement passer par un dynamic_cast pour vérifier si l'instance renvoyée et bien un VDrawer2d ou un VDrawer3d qui eux possèdent bien une méthode kill().

    A voir si tu n'as pas un problème de conception ?

  3. #3
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    Tout d'abord, merci de ta réponse.

    Citation Envoyé par Noxen Voir le message
    Je voudrais être sûr de comprendre : VEngine::getInstance() renvoie un singleton de VEngine, et dessus getVideoDrawer() renvoie un singleton de VDrawer ? Dans ce cas, je pense que la syntaxe serait plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    VEngine::getInstance()->getVideoDrawer()->kill();
    Effectivement, getVideoDrawer renvoi un singleton du drawer sélectionné. Ta solution est effectivement la plus simple, mais elle nécessite de rajouter une deuxième fonction kill non static dans VDrawer2d/3d ou dans Singleton. Je n'aime pas avoir deux fonctions avec la même utilité, je considère cela comme de la bidouille, et tout le problème vient de là, néanmoins, je pourrais aussi supprimer la méthode statique et ne garder que la méthode non-statique. C'est d'ailleurs tout à fait envisageable comme solution avec comme unique risque de devoir à un instant charger le singleton pour pouvoir le détruire (dans le cas où il n'est pas encore instancié).
    Je pense que je vais faire comme ça, mais je voudrais tout de même savoir s'il est possible d'utiliser une méthode statique d'une classe fille à partir d'un pointeur de son instance (quand la méthode statique est déclarée dans la classe mère).

    ... mais c'est peut-être encore plus simple comme ça :
    si VDrawer est bien un singleton.
    Dans ce cas si, VDrawer n'est pas un singleton alors que toute ses filles le seront à coup sure. C'est peut-être en effet un défaut de conception, mais je ne vois pas comment passer outre (toute suggestion bienvenue) car je devrais définir VDrawer comme classe template pour que ces filles puissent aussi être des singletons. Dans ce cas, je serais obligé de déclaré le pointeur vers VDrawer avec son paramètre de template pointant soit vers VDrawer2d, soit vers VDrawer3d, ce qui supprimerait l'intérêt du Builder VDrawer car on ne pourrait plus choisir dynamiquement entre VDrawer2d et VDrawer3d (sauf en utilisant 2 variables).

    Ceci-dit, si VDrawer n'hérite pas de Singleton, et qu'il ne déclare pas une méthode kill(), je pense pas que ça puisse marcher aussi facilement ; il te faudra probablement passer par un dynamic_cast pour vérifier si l'instance renvoyée et bien un VDrawer2d ou un VDrawer3d qui eux possèdent bien une méthode kill().
    Hehe, je suis bien dans ce cas si: VDrawer2d/3d héritent toutes les deux à la fois de VDrawer et de Singleton Le problème reste le même que dans le paragraphe précédent avec un dynamic_cast: il faudra obligatoirement définir le cast en VDrawer2d ou VDrawer3d, ce qui enlève encore une fois l'utilité d'un builder.

  4. #4
    Membre confirmé Avatar de deeal
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    218
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 218
    Par défaut
    si c'est une methode static, tu n'as pas besoin de retourner une instance de quoi que ce soit non
    pourquoi tu n'appelles pas directement
    VDrawer::kill()?

    D

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    Salut,

    A vrai dire, j'ai énormément de mal à comprendre pourquoi passer par une instance de singleton pour... obtenir l'instance unique d'un autre singleton...

    De toute évidence, tu a mal évalué les responsabilités de tes classes et les relations qui les unissent

    Il se peut qu'un singleton doive s'assurer de l'existence d'un autre (voir le fiasco dans l'ordre d'initialisation, dans la fAQ), mais, de manière générale, si un objet doit avoir un comportement polymorphe mais n'exister que sous la forme d'une instance unique, il ne faut jamais que la classe de base de cet objet soit un singleton.

    Si un singleton doit gérer un objet polymorphe, il doit avoir comme seule responsabilité la création et la destruction de l'objet en question, et la seule relation qui peut exister entre le singleton et la classe de base serait de l'ordre de la composition.

    Au final, cela pourrait ressembler à
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    /* une classe rajoutée: un singleton qui "porte" l'objet polymorphe */
    class DrawHolder
    {
        public:
            static DrawHolder& instance()
            {
                if(!inst)
                    inst = new DrawHolder;
                return *inst;
            }
            static void kill
            {
                delete inst;
                inst = NULL;
            }
            /* méthode (non statique) renvoyant le Drawer */
            Drawer* view()
            {
                return draw;
            }
            /* méthode (non statique) permettant de changer la vue */
            void changeView()
            {
                d3 = d3^1; // fait passer d3 de true à false et inversément
                /* libere la mémoire de la vue précédente */
                delete draw;
                /* alloue la mémoire à la nouvelle vue; */
                draw = (d3? new Drawer3D ; new Drawer2D);
            }
        private:
            /* par défaut, nous considérons que la vue sera 3D */
            DrawHolder():d3(true) 
            {
                draw = new Drawer3D;
            }
            ~DrawHolder()
            {
                delete draw;
            }
            Drawer* draw;
            bool d3; /* permet de savoir si l'affichage est effectué en 3D
    }
    Et nous aurions l'arborescence suivante au niveau des Drawer:
    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
    class Drawer
    {
        public:
        /* tout ce qui "va bien" */
        virtual void draw();
    };
    class Drawer2D : public Drawer
    {
        public:
            virtual void Draw();
    };
    class Drawer3D : public Drawer
    {
        public:
            virtual void Draw();
    };
    Le singleton tel que représenté s'écarte fortement du pattern builder, mais il peut très facilement finir par s'en rapprocher, si tu rajoute des méthodes (non statiques) qui permettent de gérer d'autre parties qui me sont restées inconnues
    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

  6. #6
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    Tout d'abord, merci de vos 2 réponses !


    Deaal:
    VDrawer::kill() ne pourrait pas fonctionner vus que VDrawer n'hérite pas de Singleton et ne comporte donc pas la méthode kill(). Ou peut-être que s'il en héritait, VDrawer::kill() aurait le même effet que VDrawer2d::kill() ?


    koala01:
    Tu as tout à fait raison ! Pas besoin de transformer ton code en builder ou quoi que ce soit, je peux le laisser comme ça en mettant les constructeurs des Drawers privés et en définissant les Drawers comme amis de l'Holder. J'ai confondu ma définition de builder avec celle d'un Factory ultra simplifié (honte à moi !).

    J'ai trouvé le problème que posait mon architecture actuelle, mais il me reste quelques questions.

    Si un singleton doit gérer un objet polymorphe, il doit avoir comme seule responsabilité la création et la destruction de l'objet en question, et la seule relation qui peut exister entre le singleton et la classe de base serait de l'ordre de la composition.
    - Ceci dût à la sémantique ou à un problème technique envisageable ? Actuellement, le seul avantage technique que je vois est que cela encapsule mieux le fonctionnement du holder.

    - Ce pattern "Holder" porte-t-il un nom ?

    En tout cas, encore merci énormément !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    C'est "simplement" un problème de conception...

    De manière générale, dans l'énorme majorité des cas, un objet n'a aucune raison d'être responsable de sa propre construction ou de sa propre destruction.

    Sa responsabilité porte sur la construction et la destruction... de ses membres.

    Mais la responsabilité de la construction ou de la destrution d'un objet est reportée... aux objets ou aux fonctions... qui utilisent cet objet.

    De plus, la relation d'héritage est la relation la plus forte qui existe en OO, et se doit donc, par la force des choses, d'être utilisée "le moins souvent possible".

    Elle représente le fait que tu puisse - sémantiquement parlant - dire que "la classe dérivée est la classe de base", qu'elle dispose de "l'ensemble des caractéristiques" de la classe de base.

    Ainsi, il est effectivement sémantiquement correct de dire que "une Vue3D est une Vue", ou que "un homme est un mammifère" ou encore que "un mammifère est un animal".

    Par contre, pour pouvoir dire que "quelque chose" (quoi que ce soit) est un singleton, il faut commencer par réfléchir à "ce qu'est un singleton".

    Un singleton est un objet
    1. global
    2. dont il n'existera jamais qu'une seule instance
    3. qui sera en tout état de cause créé très tot dans l'application
    4. qui ne sera généralement détruit qu'à la fin de l'application
    5. qui sera responsable - en plus de la création de ses membres - de sa propre création et de sa propre destruction

    Et là, s'il est effectivement possible de dire qu'une vue peut etre globale et créée très tôt dans l'application, on se rend compte que, si on travaille sur un objet polymorphe, il serait tout à fait faux de dire qu'il ne sera détruit qu'à la fin de l'application.

    En effet, la notion même d'objet polymorphe est représentée comme le fait de pouvoir faire passer un objet pour "un autre", et qu'elle n'a donc de sens que... si l'on reste libre de décider le moment de la création ou de la destruction.

    Il est donc impossible de décider qu'un objet polymorphe soit responsable de sa propre création et de sa propr destruction.

    Comme on ne peut pas dire qu'une vue (qu'elle soit 2D ou 3D) aura exactement toutes les caractéristiques d'un singleton, tu ne pas envisager la relation d'héritage.

    Il faudra donc envisager "autre chose" qui puisse n'exister en tout état de cause qu'en une instance unique et qui aura comme responsabilité la (re)création et la destruction d'une instance de ta vue de veiller à la garder unique.

    Ensuite, il reste tout à fait possible de décider - au choix - que cet "autre chose" a sa propre existance "naturelle" (qu'il s'agit d'un singleton) ou, qu'il soit groupé à d'autres objet unique au sein d'un autre objet qui serait lui un singleton... le résultat final resterait le même.

    Quant à savoir s'il existe un nom de pattern pour représenter les "gestionnaires", il en existe plusieurs.

    Cela peut aller du pattern "observateur" au pattern "mediateur", en passant finalement par l'ensemble des pattern dits "comportementaux" ou "de creation"...

    Tôt ou tard, dans ces différents patterns, tu va faire intervenir la notion de "gestionnaire" des objet créé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

  8. #8
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    Merci pour ce raisonnement poussé, je suis bluffé ! Je vois que j'ai encore énormément de choses à apprendre. Y a-t-il un endroit où apprendre ce genre de choses en autodidacte ? Les livres sur les designs patterns vont-ils si loin dans le détail ?

    En tout cas, je te remercie encore ! Je note le sujet comme résolu.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 641
    Par défaut
    Citation Envoyé par k4dw4 Voir le message
    Merci pour ce raisonnement poussé, je suis bluffé ! Je vois que j'ai encore énormément de choses à apprendre. Y a-t-il un endroit où apprendre ce genre de choses en autodidacte ? Les livres sur les designs patterns vont-ils si loin dans le détail ?
    Une chose est sure, l'héritage est presque toujours considéré comme une relation "est un(e)"...

    Certains bouquins tentent de mettre en garde sur la sémantique de cette relation, en faisant - à juste titre - remarquer que si "A est un B", on peut aussi dire que "A a toutes les caractéristiques de B", et c'est la raison pour laquelle je me base volontiers sur la sémantique des types pour lesquels j'envisage l'héritage.

    Le problème des bouquins, c'est que, bien souvent, il est difficile d'arriver à être complet lorsque l'on est limité dans le nombre de pages.

    De plus, c'est humain, il est souvent très difficile de croire une personne qui prétende connaitre "dans ses moindres recoins" un champs aussi vaste que la programmation (en générale) ou un langage de programmation (en particulier).

    Même les bouquins écrits avec plusieurs co-auteurs risquent malgré tout - bien que le risque diminue (du moins quand les co-auteurs savent réellement de quoi ils parlent) - d'aller un peu moins en profondeur sur un aspect ou un autre, ou de partir d'un point de vue erroné. Et le phénomène est encore pire lorsqu'il s'agit de traduction, car, aux approximations des auteurs, viennent s'ajouter les mécompréhensions ou les interprétations douteuses de la part des traducteurs (qui ne sont pas forcément des programmeurs ou des développeurs).

    Tout cela pour dire que tu trouvera parfois des bouquins qui "iront un peu plus dans le détail" que d'autres, mais qu'à coté de cela, c'est surtout ta propre expérience qui sera décisive dans ta "compétence" à la conception ou à la programmation.

    De plus, comme tu l'a si bien dit, mon message était un raisonnement... Ce qui implique que je suis parti d'hypothèses - normalement vérifiées, vérifiables ou communément admises - afin de faire la démonstration d'une thèse donnée.

    Si nous pouvons te donner "les bonnes bases", les bons conseils, les hypothèses les plus communément admises, nous ne pourrons que très difficilement t'apprendre à réfléchir par toi même (bien que je ne sous entende absolument pas que tu ne sache pas le faire... n'y vois aucune attaque, hein )

    Nous pouvons - en accord avec ma signature - essayer de te faire comprendre correctement quelque chose, essayer de te permettre de pouvoir l'énoncer clairement, mais, au delà, l'exploitation que tu pourra faire de ce que l'on t'aura "appris" dépendra grandement de ta capacité propre (sur laquelle, encore une fois, je n'émet aucun jugement, nous sommes bien d'accord ) à "sérier" correctement ce que tu sais et à l'utiliser "à bon escient"...
    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

  10. #10
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    "Ce n'est pas parce qu'on connaît les notes de musique que l'on sait les chanter." n'est-ce pas ? ;-), mais je pense que cela vient avec la pratique.

    Quant au problème des bouquins "impertinents", je pense que la solution réside dans la lecture simultané de plusieurs d'entre eux sur un sujet donné. Je vais passer à la bibliothèque voir si on peut trouver des bouquins sur les design patterns (malheureusement, ça m'étonnerait et je vais devoir user de mon porte monnaie).

    Maintenant, c'est vrai que tu m'as proposé le bon plan: me référer à des personnes plus compétentes que moi pour me guider dans mon apprentissage, mais c'est contre ma nature. Je vais devoir apprendre à "doser" les questions que je pose.

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 24/05/2011, 11h05
  2. Réponses: 4
    Dernier message: 10/10/2010, 11h46
  3. Utiliser une méthode non-static dans une méthode static
    Par mcfly37 dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 18/08/2010, 11h41
  4. Réponses: 2
    Dernier message: 05/03/2010, 14h15
  5. Réponses: 2
    Dernier message: 26/02/2008, 18h28

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