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 :

[débutante] Pattern visiteur


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 16
    Points : 10
    Points
    10
    Par défaut [débutante] Pattern visiteur
    Bonjour j'ai longtemps cherché avant de tomber sur ce poste qui je pense correspond à mon problème mais n'y répond pas tout à fait.
    Je suis débutante en C++ ainsi qu'en POO, et je n'ai encore jamais crée de template.

    Voilà mon problème:

    J'aimerai implémenter le pattern visiteur en c++, pour cela j'ai crée une interface IVistor et j'implémente la classe CPGResolutionVisitor qui hérite de mon interface. Jusque là tout va bien.

    Ensuite arrive le gros problème. Parmi les objets que mon visiteur doit visiter il y a des objets abstraits. Et en fonction de la structure d'objets que je crée je veux que mon visiteur visite les classes filles de mes classes abstraites. Or avec une interface je déclare des fonctions virtuelles pure, et je dois conserver exactement la même signature dans mes classes filles, ce qui n'est pas le cas ici.

    Faut-il donc qu'en plus d'hériter de IVisitor, ma classe CPGResolutionVisitor hérite aussi de Network, Node et IBody ?

    Mon autre problème c'est que mon visiteur concret quand il va aller visiter les objet de type Network, Node et IBody doit pouvoir acceder a des éléments qui sont spécifiques aux classes filles, donc si dans la classe CPGResolutionVisitor je laisse les type de base au lieu des types spécifiques Neuron, NaoBody, CPG je ne pourrais pas dans l'implémentation de la fonction visit faire ce que je veux faire ! Alors que faire ? (désolé pour la rime pourri)

    C'est peut-être un peu brouillon, j'avoue que j'ai un peu de mal à organiser ma pensée. J'éspère ne pas m'être trompé d'endroit pour poster (j'ai préféré venir sur un post similaire au mien plutôt que d'en créer un nouveau où on me dirait de venir voir ici).
    Merci d'avance pour votre aide aussi infime soit-elle.


    Dans le cas du CPGResolutionVisitor, mon Network est de type CPG, mon Node est de type Neuron et mon IBody est de type NaoBody.

    voilà mon 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
    22
     
    class IVisitor {
    public:
    	virtual void visit(Node* node)=0;
    	virtual void visit(Layer* layer) = 0;
    	virtual void visit(Network* net)=0;
    	virtual void visit(System* sys) = 0;
    	virtual void visit(IBody* body)=0;
    };
     
    class CPGStateResolutionVisitor: public IVisitor {
    public:
    	CPGStateResolutionVisitor();
    	CPGStateResolutionVisitor(double t0);
    	virtual ~CPGStateResolutionVisitor();
     
    	void visit(Neuron* node);
    	void visit(Layer* layer);
    	void visit(CPG* net);
    	void visit(System* sys);
    	void visit(NaoBody* body);
    };

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

    Informations professionnelles :
    Activité : aucun

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

    Tu devrais déjà veiller à ce que chaque classe n'ait qu'une responsabilité qui lui est propre, mais qu'il la remplisse correctement.

    Ainsi, un visiteur ne devrait jamais avoir comme responsabilité que... de visiter des objet d'un même type (ou assimilables).

    Ainsi, étant donné que Node, Layer, System, Network et IBody correspondent vraisemblablement à des types clairement distincts, il faudrait prévoir un visiteur par famille (un pour les Node, un pour les Layer, un pour les objets System, un pour les objet Network, et un pour les objet IBody).

    Tu peux, bien sur, te dire que, quel que soit l'objet que tu va manipuler, l'objectif du visiteur sera... de visiter l'objet, mais ce n'est pas suffisant pour estimer que tous les visiteurs particuliers ont une classe de base commune.

    C'est à ce niveau que les template peuvent te venir en aide.

    En effet, si, quelque soit le type T, tu décide que ton visiteur doit appeler une fonction visit, tu peux partir sur base d'une interface proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<class T>
    class visitor
    {
        public:
            void visit(T const & t){t.visit();}
    };
    de cette manière, lorsque tu voudra visiter des objets de types noeuds, tu pourra travailler sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main()
    {
        std::vector<Node*> tab;
        /* tu remplis ton tableau de noeuds de différents types ici */
        visitor<Noeud> visitor;
        for(std::vector<Node*>::const_iterator it=tab.begin();it!=tab.end();
            ++it)
            visitor.visit( *(*it) );
        /* il ne faudra pas oublier de libérer correctement la mémoire des pointeurs
         */
        return 0;
    }
    Et, si, à un moment donné, ce ne sont pas des Node* mais des Layers, la seule différence tiendra dans le fait que tu déclarera visitor sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    visitor<Layer> visitor;
    (idem pour les autres familles de types que tu manipule)

    Cependant, tu ne pourra envisager d'utiliser ton visiteur que sur des objets qui disposent... d'une fonction membre visit()

    L'idiôme PImpl et l'idiôme que l'on appelle CRTP (curriously Recurying Template Pattern) pourront te venir en aide.

    En effet, pour la familles de Node, tu auras une hiérarchie de classe 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
    /* l'interface des noeuds */
    class INode
    {
        /*...*/
    };
    /* et les noeuds qui en dérivent */
    class ConcreteNodeA : public Node
    {
        /* ... */
    };
    class ConcreteNodeB : public Node
    {
        /* ... */
    };
    Et, bien sur, tu aura une hiérarchie similaire pour les Layers et pour les objets System, Network et autres

    Mais, encore une fois, même si un noeud un layer, un objet système ont tous la particularité d'être visitables, ce n'est pas une raison pour... qu'un noeud, un objet système ou un layer aient une base commune.

    Tu vas donc créer une interface template qui aura pour objectif de fournir la fonction visit à tes objets, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <class T>
    class Visitable
    {
        public:
            virtual void visit() const = 0;
    };
    Puis, pour éviter l'explosion des classes, et en partant du principe que les différentes interfaces (INode, ILayers, ISystem, ... ) fournissent tout ce qu'il faut pour permettre de le visiter, tu créera une classe visitable correspondante (VisitableNode, VisitableLayer, VisitableSystem, ... ) qui hérite chaque fois de l'interface visitable, et qui est construit en prenant un pointeur sur l'objet à visiter sous des formes proches 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
    33
    34
    35
     
    /* pour les node */
    class VisitableNode :public Visitable<Node>
    {
        public:
            VisitableNode(Node* n):n_(n){}
            /* !!! ATTENTION le destructeur ne doit absolument pas invoquer 
             * delete sur le pointeur :D
             */
            virtual void visit() const;
            {
                n_->doSomething();
                n_->secondThingToDo();
                n_->thirdThingToDo();
                /* ...*/
            }
        private:
            Node * n_;
    };
    /* pour les layers */
    class VisitableLayer :public Visitable<Layer> 
    {
        public:
            VisitableLayer(Layer* n):n_(n){}
            virtual void visit() const;
            {
                n_->doSomething();
                n_->secondThingToDo();
                n_->thirdThingToDo();
                /* ...*/
            }
        private:
            Layer * n_;
    };
    /* et ainsi de suite */
    et l'utilisation deviendra alors proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main()
    {
        std::vector<Node*> tab;
        /* tu remplis ton tableau de noeuds de différents types ici */
        visitor<VisitableNode> visitor;
        for(std::vector<Node*>::const_iterator it=tab.begin();it!=tab.end();
            ++it)
            visitor.visit( VisitableNode(*it) );
        /* il ne faudra pas oublier de libérer correctement la mémoire des pointeurs
         */
        return 0;
    }
    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

  3. #3
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 16
    Points : 10
    Points
    10
    Par défaut
    C'est dense !

    je l'ai relu plusieurs fois pour être de bien tout comprendre !!!

    Pour ce qui est de mes classes Node, Layer, System, Network et IBody, en fait j'ai la structure suivante (j'ai pas mal élagué pur que le code soit plus clair, et tu as le droit de me taper sur les doigts vu que je ne respecte pas tellement les règles de nommage [ex:Network au lieu de INetwork]) :

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
     
     
    class Node {
    protected:
        double output_;
        vector<double> input_;
    public:
        Node();
        virtual ~Node();
     
        virtual void accept(IVisitor&)=0;
    };
     
    class Neuron: public Node {
    private:
        int number_;
        double state_;
        double vi_;
    public:
        Neuron();
        Neuron(int);
        ~Neuron();
        void accept(IVisitor&);
    };
     
    class Oscillator: public Node {
    private:
        vector<Neuron*> neurons_;
    public:
        Oscillator();
        ~Oscillator();
     
        void accept(IVisitor&);
    };
     
    class Layer {
    private:
        vector<Neuron*> node_;
        int number_;
    public:
        Layer();
        Layer(int);
        Layer(vector<Neuron*>, int, NetworkMap*);
        ~Layer();
     
        void accept(IVisitor& );
    };
     
    class Network {
    protected:
        string name_;
        vector<Layer*> layers_;
    public:
        Network();
        Network(string name);
        virtual ~Network();
     
        virtual void accept(IVisitor&)=0;
    };
     
    class CPG: public Network {
    private:
        double u0_;
        double beta_;
        vector<double> tcis_;
        vector<double> tcae_;
    public:
        CPG();
        CPG(string name);
        ~CPG();
     
        void accept(IVisitor& );
    };
     
    class IBody {
    protected:
        Network* net;
        System* sys;
    public:
        virtual void accept(IVisitor&)=0;
    };
     
    class NaoBody: public IBody {
    public:
        NaoBody();
        ~NaoBody();
     
        void accept(IVisitor&);
    };
    Toutes mes classes sont liées entre elles. IBody est en fait un genre de composite je dirais.

    Pour construire mon visiteur j'ai lu la fiche pattern visitor sur wikipedia : http://en.wikipedia.org/wiki/Visitor_pattern
    L'exemple est en java certes mais bien expliqué je trouve.
    Je m'en suis très largement inspiré pour faire mon visiteur.

    D'après ce que j'ai compris à la première lecture de ton post et après relecture de la fiche wiki c'est qu'en fait je me suis déjà complètement mélangée. Si j'avais voulu copier tout à fait l'exemple wiki il aurait fallut que je fasse une interface supplémentaire avec juste la méthode accept() que toutes mes classes devraient alors implémenter.

    Le problème c'est que même si elle sont liés elles sont clairement distinctes si j'ai bien compris, et c'est pour ça que j'aurais besoin d'un template.

    Grâce à ton poste je comprend mieux comment marchent les template et le pattern visiteur.

    j'ai quand même encore des questions (c'est de ma faute je m'en rend compte je n'ai pas été assez précise dans mon post de départ).

    VisitableNode(Node* n):n_(n){}
    /* !!! ATTENTION le destructeur ne doit absolument pas invoquer
    * delete sur le pointeur
    */
    C'est parce que c'est la fonction delete du template qui va tuer le pointeur, et que donc si j'invoque le destructeur dans la classe visitableNode la console va m'insulter en me disant que j'essaie de détruire un pointeur qui a déjà été détruit ?

    Ensuite, j'utilise mon visiteur pour faire des calculs importants. Et l'idée c'est que j'ai besoin à la fois des informations qui sont dans mon réseau de neurone et dans ma classe système. L'idée c'est que par l'intermédiaire de Body j'ai accès au réseau et au système en même temps. Je fais mes calculs, je met à jour mon système et mon réseau et je repars faire autre chose.
    Donc en fait en reprenant ton exemple, il faudrait qu'en plus dans ma fonction visit de la classe VisitableBody j'instancie une classe VisitableSystem qui hériterait du template que j'aurais typé en System et qui appellerait sa propre fonction visit() et ainsi de suite.

    Est ce que je suis à côté de la plaque ou est-ce que ça te paraît correcte ?

    Encore une fois merci pour ta réponse. Je vais pouvoir avancer dans mon projet grâce à toi

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par ghani56 Voir le message
    C'est dense !
    Effectivement, mais il fallait essayer d'être un minimum complet
    je l'ai relu plusieurs fois pour être de bien tout comprendre !!!
    Cela ne métonne qu'à moitié, ce que j'ai essayé d'expliquer fait déjà partie de ce que l'on pourrait qualifier comme s'adressant à des "débuttant initiés"
    Pour ce qui est de mes classes Node, Layer, System, Network et IBody, en fait j'ai la structure suivante (j'ai pas mal élagué pur que le code soit plus clair, et tu as le droit de me taper sur les doigts vu que je ne respecte pas tellement les règles de nommage [ex:Network au lieu de INetwork]) :

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
     
     
    class Node {
    protected:
        double output_;
        vector<double> input_;
    public:
        Node();
        virtual ~Node();
     
        virtual void accept(IVisitor&)=0;
    };
     
    class Neuron: public Node {
    private:
        int number_;
        double state_;
        double vi_;
    public:
        Neuron();
        Neuron(int);
        ~Neuron();
        void accept(IVisitor&);
    };
     
    class Oscillator: public Node {
    private:
        vector<Neuron*> neurons_;
    public:
        Oscillator();
        ~Oscillator();
     
        void accept(IVisitor&);
    };
     
    class Layer {
    private:
        vector<Neuron*> node_;
        int number_;
    public:
        Layer();
        Layer(int);
        Layer(vector<Neuron*>, int, NetworkMap*);
        ~Layer();
     
        void accept(IVisitor& );
    };
     
    class Network {
    protected:
        string name_;
        vector<Layer*> layers_;
    public:
        Network();
        Network(string name);
        virtual ~Network();
     
        virtual void accept(IVisitor&)=0;
    };
     
    class CPG: public Network {
    private:
        double u0_;
        double beta_;
        vector<double> tcis_;
        vector<double> tcae_;
    public:
        CPG();
        CPG(string name);
        ~CPG();
     
        void accept(IVisitor& );
    };
     
    class IBody {
    protected:
        Network* net;
        System* sys;
    public:
        virtual void accept(IVisitor&)=0;
    };
     
    class NaoBody: public IBody {
    public:
        NaoBody();
        ~NaoBody();
     
        void accept(IVisitor&);
    };
    Toutes mes classes sont liées entre elles. IBody est en fait un genre de composite je dirais.
    Pour les conventions de nommages, il faut te dire que, de toutes manières, chacun peut avoir les siennes (pour autant qu'elles soient stables sur toute la durée du projet)...

    Par contre, il faut comprendre qu'il existe plusieurs "liaisons" possible entre tes différentes classes:

    L'héritage (que tu utilises, par exemple entre Node et Neuron ou Oscilliator, et entre Network et CPG ) est la relation la plus forte qui puisse exister entre deux classes, parce qu'elle représente le fait qu'un Neuron ou un Oscilliator (selon ton exemple) peut se faire passer pour un Node, ou qu'un CPG peut se faire passer pour un Network.

    A ce titre, je rappelle encore une fois le principe de substitution de Liskov (que l'on connait aussi sous l'acronyme LSP) qui dit que, pour que l'on puisse envisager l'héritage, il faut que toute propriété valide pour la classe de base (ici: Node ou Network) doit l'être pour la classe dérivée (ici: respectivement Neuron, Oscilliator ou CPG)

    Cela implique que, si tu as un comportement quelconque dans Node, il faut que ce comportement puisse s'appliquer (éventuellement en s'adaptant au type réellement manipulé) à Neuron ou à Oscilliator.

    L'héritage crée une "hiérarchie" des classes dans laquelle tu peux parler de "classe mère /ancêtre / de base" pour la classe la plus haute dans la hiérarchie (ici: Node ou Network) et de "classe enfant / dérivée" pour les classes qui en héritent (respectivement Neuron, Oscilliator et CPG)

    Puis, tu as des relations plus "souples", qui représentent le fait d'une relation "contenant à contenu", et que l'on appelle, selon le cas, "agrégation" ou "composition".

    Pour être tout à fait complet, la différence entre les deux tient au fait que l'une (l'agrégation) implique que le contenu peut survivre au contenant et que l'autre (la composition) implique au contraire que le contenu est intimement lié au contenant: lorsque le contenant est détruit (ou copié), le contenu l'est également

    C'est le type de relation qui relie ta classe Layer à ta classe Node, ta classe Network à ta classe Layer et ta classe IBody à tes classes Network et System.

    *Idéalement*, l'idée est de faire un visiteur par hiérarchie de classe.

    La raison est, finalement, relativement simple: Si une fonction ou une classe a plus d'une responsabilité, c'est sans doute que cette fonction ou cette classe en a trop.

    Le fait est que, si tu décides effectivement de créer un visiteur par hiérarchie de classe, tu va te retrouver avec un NodeVisitor, un NetworkVisitor, un LayerVisitor et un IBodyVisitor, que tu devra à chaque fois créer et qui reviendra à... faire un monstrueux copier / coller du premier, en adaptant le type à visiter.

    En effet, la seule différence qui peut exister entre tous ces visiteurs est... le type d'objet visité, alors que le comportement en lui-même reste strictement identique.

    C'est en cela que la programmation générique (AKA: les template) peuvent t'aider énormément

    Pour construire mon visiteur j'ai lu la fiche pattern visitor sur wikipedia : http://en.wikipedia.org/wiki/Visitor_pattern
    L'exemple est en java certes mais bien expliqué je trouve.
    Je m'en suis très largement inspiré pour faire mon visiteur.
    Et tu n'a pas mal fait...

    Mais il faut savoir que Java place certaines restrictions qui font que tu "perds" une partie de la puissance et de la souplesse du C++:

    Il ne s'agit pas ici de relancer l'éternel débat entre le C++ et le Java, mais java ne supporte ni l'héritage multiple, ni le paradigme de programmation générique.

    Or, justement, comme il y a plusieurs hiérarchies de classes, ces possibilités prennent un attrait particulier

    D'après ce que j'ai compris à la première lecture de ton post et après relecture de la fiche wiki c'est qu'en fait je me suis déjà complètement mélangée. Si j'avais voulu copier tout à fait l'exemple wiki il aurait fallut que je fasse une interface supplémentaire avec juste la méthode accept() que toutes mes classes devraient alors implémenter.
    Effectivement
    Le problème c'est que même si elle sont liés elles sont clairement distinctes si j'ai bien compris, et c'est pour ça que j'aurais besoin d'un template.
    Tu as tout compris
    Grâce à ton poste je comprend mieux comment marchent les template et le pattern visiteur.
    C'est le but

    C'est parce que c'est la fonction delete du template qui va tuer le pointeur, et que donc si j'invoque le destructeur dans la classe visitableNode la console va m'insulter en me disant que j'essaie de détruire un pointeur qui a déjà été détruit ?
    C'est surtout parce que tes objets doivent continuer d'exister après avoir été visités.

    La durée de vie de tes objets doit n'être gérée que par un classe particulière (en gros, celle qui regroupe la collection d'objet )

    Si, tu invoque delete sur l'objet pointé par VisitableNode (ou toute autre classe similaire, pointant sur un objet adapté), ton tableau de Node* va contenir des pointeurs vers... quelque chose qui aura été déjà détruit, et cela enverra ton programme cueillir les marguerites
    Ensuite, j'utilise mon visiteur pour faire des calculs importants. Et l'idée c'est que j'ai besoin à la fois des informations qui sont dans mon réseau de neurone et dans ma classe système. L'idée c'est que par l'intermédiaire de Body j'ai accès au réseau et au système en même temps. Je fais mes calculs, je met à jour mon système et mon réseau et je repars faire autre chose.
    Donc en fait en reprenant ton exemple, il faudrait qu'en plus dans ma fonction visit de la classe VisitableBody j'instancie une classe VisitableSystem qui hériterait du template que j'aurais typé en System et qui appellerait sa propre fonction visit() et ainsi de suite.
    C'est l'idée, en effet:

    Pour chaque objet qui peut être visité, il faut:
    • un visiteur qui se charge de le visiter
    • rendre ton objet visitable (autant que faire se peut, en utilisant la classe de base de la hiérarchie)

    Est ce que je suis à côté de la plaque ou est-ce que ça te paraît correcte ?
    Ca me parrait correct
    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 à l'essai
    Inscrit en
    Août 2008
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 16
    Points : 10
    Points
    10
    Par défaut
    L'héritage (que tu utilises, par exemple entre Node et Neuron ou Oscilliator, et entre Network et CPG ) est la relation la plus forte qui puisse exister entre deux classes, parce qu'elle représente le fait qu'un Neuron ou un Oscilliator (selon ton exemple) peut se faire passer pour un Node, ou qu'un CPG peut se faire passer pour un Network.
    De ce coté là c'est bon je pense. Un CPG est un genre particulier de reseau de neurone (Network). En fait dans un reseau de neurones ce qui est constant c'est qu'il est composé de couches (Layer) et sur ces couches il y a des neurones (Neuron). Apres ces neurones peuvent soit etre des neurones tout seules soit des neurones qui sont agencés de façon à faire un ou plusieurs oscillateurs, c'est pour ça que j'ai la classe Node. Apres, chaque type de reseau a sa propre architecture de layer et de neurones. Apres un body représente un robot en général. Dans chaque robot j'ai un cerveau (le réseau de neurone) et un corps physique (le systeme). Body n'est qu'une interface au final. Apres chaque type de robot aura son systeme propre (telle masse, telle longueur de membres ... et en fonction des matieres, des éléments de frictions qui sont différents ...) et un cerveau qui lui est propre.

    La durée de vie de tes objets doit n'être gérée que par un classe particulière (en gros, celle qui regroupe la collection d'objet )

    Si, tu invoque delete sur l'objet pointé par VisitableNode (ou toute autre classe similaire, pointant sur un objet adapté), ton tableau de Node* va contenir des pointeurs vers... quelque chose qui aura été déjà détruit, et cela enverra ton programme cueillir les marguerites
    ok, compris ^^

    Pour chaque objet qui peut être visité, il faut:

    * un visiteur qui se charge de le visiter
    * rendre ton objet visitable (autant que faire se peut, en utilisant la classe de base de la hiérarchie)
    Ok, compris !

    Dernière question, comme Node, Network et Body ne servent au final que d'interface et que je ne les instancierai jamais, et que quand je monterai un robot (Body) je n'utiliserai que des instances de leurs filles donc je n'aurais pas de VisitableNode, VisitableBody, VisitableNetwork mais que des VisitableNeuron, VisitableOscillator, VisitableCPG, visitableNao , VisitableClasseFilleDeNetwork ...... ?

    Merci beaucoup pour toutes tes réponses qui m'aident à voir plus clair sur le fonctionnement du c++et des design pattern !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par ghani56 Voir le message
    Dernière question, comme Node, Network et Body ne servent au final que d'interface et que je ne les instancierai jamais, et que quand je monterai un robot (Body) je n'utiliserai que des instances de leurs filles donc je n'aurais pas de VisitableNode, VisitableBody, VisitableNetwork mais que des VisitableNeuron, VisitableOscillator, VisitableCPG, visitableNao , VisitableClasseFilleDeNetwork ...... ?
    Pas forcément: si, pour visiter un Neuron ou un Oscilliator, tu peux n'appeler que des fonctions polymorhpes qui sont déclarées dans ton interface Node et adaptées au fait que c'est soit un Neuron soit un Oscilliator, tu as intérêt à ne créer qu'une classe VisitableNode, qui manipule... un Node (sans précision).

    Si Node contient une fonction membre virtuelle pure et est donc une classe abstraite, la seule chose que tu ne puisse pas faire, c'est créer une instance de cette classe ( Node n; t'est interdit).

    Par contre, tu peux manipuler des pointeurs et / ou des références de type Node, et c'est là que le polymorphisme entre en jeu.

    En effet, Neuron et Oscilliator peuvent parfaitement se faire passer pour des... Node:

    Tu peux en effet 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
    23
    24
    25
    26
     
    /* un neurone est un noeud et peut donc se faire passer comme tel */
    Node * ptr1 = new Neuron;
    /* un oscilliateur est un noeud et peut donc se faire passer comme tel */
    Node * ptr2 = new Oscilliator;
    /* voire : */
     Neuron n;
     Oscilliator o;
     Node *ptr3=&n;
     Node *ptr4=&o;
     VisitableNode v1(ptr1);
    visitableNode v2(ptr2);
    VisitableNode v3(ptr3);
    VisitableNode v4(ptr4)
    v1.visit(); /* visite le neurone */
    v2.visit(); /* visite l'ocsilliateur */
    v3.visit(); /* visite ... n (un neurone) */
    v4.visit(); /* visite ... o (un oscilliateur) */
    /* n'oublions pas ici de détruire ptr1 et ptr2 */
    delete ptr1;
    delete ptr2;
    ptr1=0;
    ptr2=0;
    /* par contre, o et n étant créés sans passer par l'allocation dynamique,
     * il n'est pas nécessaire d'invoquer delete sur eux
     */
    La classe VisitableNode pouvant visiter "n'importe quel type de Node", pourra donc visiter aussi bien des Neuron que des Oscilliator, en utilisant le polymorphisme et qui t'évite d'avoir à gérer une classe visitable par classe à visiter.

    Par contre, si pour pouvoir visiter Neuron ou Oscilliator, tu dois faire appel à une fonction membre qui est propre à Neuron ou à Oscilliator, tu n'auras effectivement pas le choix: il faudra effectivement disposer d'une classe "visitable" séparée qui appelle les bonnes fonctions.
    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

  7. #7
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 16
    Points : 10
    Points
    10
    Par défaut
    Merci beaucoup pour toutes tes réponses ! Tes explications étaient très claire !
    Grâce à toi je peux avancer dans mon projet ^^
    Et je sais que ça me servira souvent à l'avenir, donc encore une fois un grand merci ^^

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

Discussions similaires

  1. [Débutant] Pattern master/details
    Par Grumium dans le forum Eclipse Platform
    Réponses: 2
    Dernier message: 19/09/2009, 10h30
  2. [Visiteur] design pattern visiteur
    Par wsdl_adr dans le forum Design Patterns
    Réponses: 1
    Dernier message: 07/10/2008, 20h41
  3. [débutant] Pattern matching avec un n-uplet
    Par coyotte507 dans le forum Caml
    Réponses: 8
    Dernier message: 29/09/2008, 07h51
  4. [Visiteur] design pattern Visiteur ou Iterateur pour parcourir une arborescence?
    Par mehdiing dans le forum Design Patterns
    Réponses: 1
    Dernier message: 29/05/2008, 17h10
  5. [Débutant] pattern singleton
    Par SirDarken dans le forum Débuter avec Java
    Réponses: 22
    Dernier message: 11/12/2004, 01h55

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