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 :

ajout d'un élément à une liste (structure)


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mai 2009
    Messages
    56
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 56
    Par défaut ajout d'un élément à une liste (structure)
    J'ai essayé de manipuler une liste en y ajoutant un élément à l'aide d'une méthode .
    La définition de la liste est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Chemin{
    	Case* laCase;
    	Chemin* suivant;
    	};
    Et le code de la méthode d'ajout est:
    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
    void Itineraire::add(Case& B)
    {
     
     
    	Chemin *nouveau_item=new Chemin;
    	nouveau_item->laCase=new Case(0,0);
    	nouveau_item->suivant=NULL;
     
     
    	nouveau_item->laCase->set_Ligne(B.get_Ligne());
    	nouveau_item->laCase->set_Colonne(B.get_Col());
    	nouveau_item->suivant=NULL;
     
     
     
    if ( chemin==NULL )
    	chemin=nouveau_item;
    else
    {
    	Chemin* auxiliaire=new Chemin;
     
    	/*auxiliaire->laCase=chemin->laCase;
    	auxiliaire->suivant=chemin->suivant;*/
     
    		for(auxiliaire=chemin; auxiliaire->suivant!=NULL;){//atteindre la fin de la liste
    			auxiliaire=auxiliaire->suivant;}
    	auxiliaire->suivant=nouveau_item;
    	}
     
     
     
     
    }
    Mon problème est que la variable chemin ne prend plus les nouveaux éléments!

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

    Informations professionnelles :
    Activité : aucun

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

    Sais tu que, en C++, une structure ne présente que très peu de différences par rapport à une classe, et que, par conséquent, tu peux parfaitement envisager de prévoir un constructeur qui te permettrait de t'éviter bien du boulot

    Je me demande d'ailleurs pourquoi tu passe par un constructeur qui pourrait être considéré comme... un constructeur par défaut (définissant ligne et colonne à 0) pour, tout de suite après, appeler un mutateur (qui, selon moi, ne devrait pas exister) sur ces deux valeurs

    En effet, une fois qu'une case a pris une position (en ligne et en colonne), on peut estimer... qu'elle la gardera, et qu'il n'est donc pas opportun d'en permettre le déplacement

    De plus, à moins que ta classe / structure Case ne nous cache quelque chose, *peut-être* serait il intéressant de créer ta structure Chemin (qui aurait d'ailleurs avantage à être renommée, car elle ne représente pas un chemin, mais plutôt une étape du chemin ) de telle manière à ce qu'elle contienne une instance de Case et non un pointeur vers une instance de Case, et donc, d'utiliser le constructeur par copie de l'objet Case (ou, à défaut, d'appeler directement le constructeur adéquat

    Enfin, j'ai l'impression que ta structure Chemin est en fait destinée à travailler comme un itérateur, et que, comme tout itérateur, ce que l'on peut lui demander, c'est:
    • de fournir l'accès à l'itérateur suivant
    • de permettre d'accéder à l'objet qu'il représente, en lui donnant, par exemple, une sémantique de pointeur.

    Au final, ta structure pourrait donc devenir une classe proche de (je la renomme )
    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
    class Etape
    {
        /* cette amitié nous permet de ne pas exposer plus que nécessaire
         * l'existance du pointeur m_next
         */
        friend class Chemin;
        public:
            Etape * operator++(){return m_next;}
            /* les opérateurs nous permettant de manipuler l'itérateur comme
             * s'il s'agissait d'un pointeur
             */
           Case & operator *(){return m_case;}
           Case const & operator *() const{return m_case;}
           Case * operator ->(){return & (operator *())};
           case const * operator ->() const {return & (operator*());}
        private:
            /* les constructeurs et le destructeur sont déclarés private, de manière
             * à n'en autoriser l'accès qu'à la classe Chemin
             */
            /* un constructeur appelant le constructeur de Case */
            Etape(int ligne, int colonne):m_case(ligne,colonne),m_next(NULL){}
            /* un autre se basant sur le constructeur par copie de Case */
            Etape(Case const & c):m_case(c),m_next(NULL){}
            /* le constructeur par copie et l'opérateur d'affectation sont déclarés
             * private et non définis (en attendant C++0x)
             */
            Etape(Etape const &);
            Etape& operator=(Etape const &);
            /* Ce qui nous permet de passer à l'itérateur suivant
             * (intervenant dans la sémantique de pointeur que l'on donne à notre
             * classe)
             */
            Case m_case;
            Etape* m_next;
    };
    Enfin, ce n'est qu'une habitude, mais, j'aime faire en sorte que mes listes fournissent l'ajout d'éléments en temps constant (pour qu'elle présente quand même un avantage par rapport aux tableaux dynamiques ), alors que, tel que tu présente le code, le temps mis à l'ajout d'un élément dépendra... du nombre d'éléments que ta liste contient déjà...

    Pour m'y aider, j'ai pris l'habitude de maintenir deux pointeur dans ma liste: le premier représentant le premier élément, et l'autre représentant le dernier.

    En ayant modifié la structure comme indiqué, la classe Chemin deviendrait 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
    class Chemin
    {
        public:
            Chemin():m_first(NULL),m_last(NULL){}
            ~Chemin()
            {
                while(m_first)
                {
                    Etape* temp=m_first->m_next;
                    delete m_first;
                    m_first=temp;
                }
            }
            void add(Case const & c)
            {
                Etape * temp=new Etape(c);
                if(!m_first)
                    m_first=temp;
                if(m_last)
                    m_last->m_next=temp;
                m_last=temp;
            }
        private:
            Etape* m_first;
            Etape* m_last;
    };
    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 averti
    Inscrit en
    Mai 2009
    Messages
    56
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 56
    Par défaut
    Vraiment,c'est génial..oui surtout d'avoir un qui explique les choses ainsi..
    Merci bien Koala!!!
    Mais si on a voulu(imposer) bien avoir "Chemin" comme structure?alors comme ça les choses deviennent plus difficiles?!

  4. #4
    Membre averti
    Inscrit en
    Mai 2009
    Messages
    56
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 56
    Par défaut
    Salut,
    il me reste un petit problème dû au fait que je n'est pas compris les redéfinitions de la classe "Etape"(Chemin pour moi) .En fait j'ai voulu afficher les éléments d'itinéraire ,comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void Itineraire::afficher(){
    	int v,d;
     
     
     
    	Chemin*	auxiliaire=depart;
    	cout<<"\n\n\n"<< auxiliaire->m_case.get_Ligne()<<"\n\n\n"<<endl;
    	 while(auxiliaire!=arrivee)
                {v=auxiliaire->get_case().get_Col();d=auxiliaire->get_case().get_Ligne();
    				cout<<("(")<<v<<(",")<<d<<("   ");
    				auxiliaire=auxiliaire->m_next;
    				}
    }
    or je me surpris que les valeurs des cases de départ changent dès la première utilisation de get_Ligne()!
    en notant bien que tu l'as utilisé dans ton code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      Chemin* temp=new Chemin(c);cout<<"\n\n\n"<<temp->m_case.get_Ligne()<<"\n\n\n"<<endl;
    et ça a bien marché.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par dingua Voir le message
    Salut,
    il me reste un petit problème dû au fait que je n'est pas compris les redéfinitions de la classe "Etape"(Chemin pour moi) .
    Je vais donc tâcher d'être plus clair.

    Je suis très attaché à la notion de responsabilité unique.

    Plus tu arrivera à créer des classes et des fonction n'ayant qu'une responsabilité unique, plus elles seront simples d'utilisation, et donc simples à implémenter (et à maintenir), et plus tu pourra envisager de les réutiliser.

    Ainsi, l'idée générale est qu'une classe, une structure ou une fonction ne doit s'occuper que d'une seule chose, mais doit... bien s'en charger.

    C'est à dire que, si tu veux créer une liste de cases appelée "chemin", il faut, en réalité, prévoir trois types bien distincts:
    • La case, qui représente la position à laquelle se trouve un objet donné
    • Le chemin, qui représente l'ensemble des positions par lesquelles un objet donné va passer pour rejoindre deux position données (que nous pouvons qualifier de "point de départ" et de "point d'arrivée") et
    • un troisième type de donnée qui permettra de relier les différentes cases entre elles pour, justement, accéder à la "case suivante" de proche en proche.

    C'est ce troisième type de données que j'ai appelé "étape"

    En effet, sémantiquement parlant, une étape présente "intuitivement" la notion "d'endroit atteint lorsque l'on a parcouru une partie de chemin", et fait donc "naturellement" le lien entre un endroit (une case) donné(e) et... le chemin qui permet de s'y rendre.

    Ensuite, il faut réfléchir aux service que l'on attend de ces différents types de données.

    Une case représente une position (sur un échiquier, par exemple). Les services que l'on attend d'elle sont: de nous donner une indication de numéro de ligne et de numéro de colonne.

    Mais les données qui nous permettent de représenter les numéros de lignes et de colonnes font partie de ce que l'on appelle "les détails d'implémentation"...

    Autrement dit, l'utilisateur du type Case ne devrait pas avoir à s'inquiéter de la manière dont c'est effectivement géré (ce pourrait être sous la forme de deux int séparés, sous celle d'un tableau de deux int, voire, pourquoi pas, sous une forme tout à fait différente )

    Une fois qu'elle est créée, la case ne se déplace pas, il n'y a donc pas lieu de permettre de changer le numéro de la ligne ou le numéro de colonne qu'elle représente.

    La responsabilité de la case est, tout simplement, de représenter une position (basée sur les lignes et les colonnes)
    Il faut donc prévoir de:
    1. pouvoir la créer (en lui donnant une valeur de ligne et une valeur de colonne)
    2. pouvoir la copier
    3. pouvoir l'assigner
    4. pouvoir la détruire
    5. pouvoir obtenir le numéro de ligne qu'elle représente
    6. pouvoir obtenir le numéro de colonne qu'elle représente

    Il faut savoir que, si on ne définit pas nous même un comportement pour [2][3] et [4] (normalement pour [1] aussi, mais avec la restriction qu'il ne peut pas prendre d'argument, et cela ne s'applique donc pas ici) le compilateur fournira "d'office" une implémentation de ces comportements qui, dans le cas présent, nous conviendra parfaitement...

    Au final, le type Case prendrait 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
    13
    14
    15
    16
    17
    18
    19
    20
    class Case
    {
        public:
            Case(int l, int c):m_linge(l),m_colonne(c)  // (1) (*) (**)
            {
            }
            /* laissons au compilateur le soin d'implémenter (2), (3) et (4) */
            int linge() const // (5)
            {
                return m_linge;
            }
            int  colonne() const // (6)
            {
                return m_colonne;
            }
        private:
            /* les "détails d'implémentation dont l'utilisateur n'a pas à s'inquiéter */
            int m_linge;
            int m_colonne;
    }
    (*) Les numéros entre parenthèses font référence aux numéro de la liste des services énumérées plus haut
    (**) cette syntaxe s'appelle une liste d'initialisation, qu'il est conseillé d'utiliser chaque fois que possible de préférence au fait d'assigner les valeurs des membres dans le corps même du constructeur. cf cette entrée de la FAQ pour en savoir d'avantage

    Cette structure serait sans doute avantageusement servie par quelques fonctions libres permettant de les comparer, 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
    13
    14
    15
    16
    17
    18
    // pour tester l'égalité
    bool operator ==(Case const & c1, Case const & c2)
    {
        return c1.ligne()== c2.ligne() && c1.colonne()==c2.colonne();
    }
    // pour tester l'inégalité
    bool operator !=(Case const & c1, Case const & c2)
    {
       return !(c1==c2);
    }
    // pour permettre un tri par ordre de "grandeur"
    bool operator <(Case const & c1, Case const & c2)
    {
        /* j'ai considéré ici que le nombre de colonnes par ligne 
         *est toujours égal 
         */
        return c1.ligne()*c1.colonne()< c2.ligne()*c2.colonne();
    }
    Intéressons nous maintenant au type de donnée permettant de parcourir les différentes cases de proche en proche que j'ai nommé Etape.

    Sa responsabilité est de faire le lien entre une case donnée et la case "suivante" à parcourir lorsque l'on emprunte le chemin

    D'abord, les service que l'on peut attendre de lui:
    1. Il faut pouvoir le construire (mais, idéalement, seule la liste devrait pouvoir le faire) (*)
    2. Il faut pouvoir le détruire (mais, encore une fois, seule la liste devrait pouvoir le faire) (*)
    3. on ne doit pas pouvoir l'assigner (**) (***)
    4. on ne doit pas pouvoir le copier(**) (***)
    5. Il doit permettre d'obtenir la case à laquelle il fait référence
    6. Il doit permettre d'accéder à l'élément suivant

    (*) Si nous arrivons à éviter que "n'importe qui" ne tente de créer une étape, nous obtenons l'assurance que l'utilisateur ne fera pas de c...ries. Le moyen "idéal" pour y arriver passe par l'amitié (cf la page de la FAQ qui en parle), et la définition des constructeurs et destructeurs dans l'accessibilité privée
    (**) il s'agit en définitive d'une conséquence de (*)
    (***) En attendant la prochaine norme (C++0x), le meilleur moyen d'y arriver est de déclarer l'opérateur d'affectation (operator = ) et le constructeur par copie ( MaClass(MaClass const&) ) dans l'accessibilité privée et de ne pas les définir

    Les détails d'implémentation qui lui permettront de fournir ces services sont:
    • le fait qu'il dispose d'une variable de type ... case
    • le fait qu'il dispose d'un pointeur vers... l'élément suivant

    Nous pourrions donc avoir une classe Etape 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
    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
    class Etape
    {
        /* donne à la classe Chemin accès à tout ce que la classe 
         * Etape contient
         */
        friend class Chemin;
        public:
            /* Les fonctions qui permettent à l'utilisateur d'utiliser la 
             * classe Etape
             */
            Case const & value() const{return m_case;}
            Etape const * next() const{return m_next;}
            /* Nous pouvons considérer la classe Etape comme...
             * un pointeur sur une variable Case...
             * les opérateurs qui nous intéressent alors 
             *    sont l'étoile " * " (pour pouvoir écrire (*monEtape).colonne() )
             *    la fleche " -> "  (pour pouvoir écrire monEtape->ligne()
             *    l'opérateur d'incrémentation (pour pouvoir écrire ++monEtape )
             * mais cela reste facultatif, et a pour seul but de faciliter
             * la vie à l'utilisateur :D
             */
            Case const & operator *() const{return m_case;}
            Case const * operator->() const{return &m_case;}
            Etape * operator++() const{return m_next;}
        private:
            /* tout ce qui n'est pas accessible à l'utilisateur
             * mais qui l'est pour la classe Chemin du fait de son amitié 
             */
            /* un constructeur créant  spécialement pour l'occasion
             * une case sur base de la ligne et de
             * la colonne
             */
           Etape(int l, int c):m_case(l,c),m_next(NULL){}
           /* un autre utilsiant le constructeur par copie de Case */
           Etape(Case const & c):m_case(c),m_next(NULL){}
           /* Le destructeur ne fait rien, mais si on veut en limiter l'acces,
            * il faut le définir dans l'accessibilité private (l'amitié déclarée
            * avec la classe Chemin permettra à cette classe uniquement
            * d'y accéder
            */
           ~Etape(){}
           /* interdisons l'assignation et la copie...
            * si l'utilisateur essaye d'y faire appel, il obtiendra une erreur
            * de compilation
            *
            * si la classe amie Chemin essaye de s'en servir, il faudra attendre
            * l'édition de liens avant de s'en rendre compte, mais, c'est déjà
            * pas si mal :D
            */
           Etape & operator=(Etape const &);
           Etape(Etape const &);
           /* et enfin, les détails d'implémentation permettant à l'Etape
            * de rendre les services que l'on attend d'elle
            */
          Case m_case;
          Etape * m_next;
    };
    Et, enfin, intéressons nous d'un peu plus près à la classe Chemin.

    Sa responsabilité est de maintenir un ensemble d'étapes par lesquelles il faut passer pour relier deux cases distinctes

    Les services que l'on attend d'elle sont donc que:
    1. On doit pouvoir la créer
    2. On doit pouvoir la détruire
    3. On peut vouloir être en mesure de la copier (*) (**)
    4. On peut vouloir être en mesure de l'assigner (*) (***)
    5. On veut pouvoir accéder à son premier élément
    6. On veut pouvoir accéder à... ce qui suit le dernier élément (****)
    7. On veut pouvoir ajouter un élément en fin de liste, si possible en temps constant
    8. ... il y a d'autres services dont on peut éventuellement avoir besoin (comme : permettre la recherche d'une étape passant par une case donnée, insérer une étape après une autre, vider la liste, ...)

    (*) ce n'est pas du tout obligatoire
    (**) si on le souhaite, il s'agira de faire en sorte que la copie et l'originale ne partagent pas les différents pointeurs (pour éviter les risques de fuite mémoire et de tentative de double libération de la mémoire)
    (***) si on le souhaite, il s'agira de faire en sorte que la mémoire qui était allouée aux éléments d'origine soit correctement libérée
    (****) le but est de permettre l'utilisation des boucle sous une forme dont l'utilisateur a l'habitude de les écrire

    Les détails d'implémentation qui nous permettront de rendre tous ces services seront:
    • Un pointeur sur... le premier élément de la liste
    • Un pointeur sur... le dernier élément de la liste (pour assurer l'ajout en temps constant)

    Au final, notre classe Chemin prendrait une forme (la précédente version était un peu incomplete ) 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
    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
     
    class Chemin
    {
        public:
            Chemin():m_first(NULL),m_last(NULL){}
            /* la copie doit se faire en profondeur, 
             * à moins qu'on ne l'interdise (1) 
             */
            Chemin(Chemin const & lhs)
            {
                // je profite des opérateur de Etape :D
                for(Etape* it=lhs.begin();it!=lhs.end();++it)
                    add(*it); 
     
            }
            /* l'assignation, à moins qu'on ne l'interdise (1)
             *
            Chemin & operator = (Chemin c) // copie inside
            {
                /* nécessite l'inclusion du fichier d'en-tête algorithm...
                 * l'idée est d'échanger les pointeurs m_first et m_last
                 * entre l'objet courent et la copie de l'objet à assigner
                 */
               std::swap(m_first,c.m_first);
               std::swap(m_last,c.m_last);
               /* c étant automatiquement détruit lorsque l'on passera
                * l'accolade fermantes, le destructeur de c sera appelé,
                * et la mémoire allouée aux différents éléments qui étaient
                * à l'origine dans l'objet courent sera correctement libérée
                */
            }
            /* le destructeur... doit veiller à correctement libérer la mémoire 
             * allouée aux différents éléments
             */
           ~Chemin()
           {
               while(m_first) //tant qu'il y a un premier élément 
               {
                   Etape * temp= m_first->m_next; // nous récupérons celui qui suit
                   delete m_first; // nous détruisons le premier élément
                   m_first=temp;  // et nous définissons celui qui le suivait comme
                                        // nouveau premier élément
               }
           } 
           /* pour ajouter un élément */
           void add(Case const & c)
           {
               /* nous créons dynamiquement une nouvelle étape  */
               Etape * temp=new Etape(c);
               /* C'est peut être le premier ajout que l'on fait...
                * dans ce cas, notre nouvelle étape devient... 
                * la première  de la liste
                */
               if(!m_first)
                   m_first = temp;
               /* si ce n'est pas le premier ajout, relions la dernière étape
                * à la nouvelle fraichement créée
                */
               if(m_last) 
                   m_last->m_next = temp;
               /* Quoi qu'il en soit, l'étape nouvellement créée devient...
                * la dernière du chemin
                */
               m_last = temp;
           }
           /* permet d'accéder à la première étape du chemin */
           Etape const * begin() const{return m_first;}
           /* permet d'accéder à ce qui suit la dernière étape */
           Etape const * end() const{return NULL;}
        private:
            /* les détails d'implémentation */
            Etape * m_first; // la première étape 
            Etape * m_last; // la dernière étape
    };
    (1) voir plus haut, ce qui est dit au sujet de la classe Etape

    La solution proposée ayant pour but de faire en sorte que chaque type d'objet n'aie jamais qu'une seule responsabilité et de "diriger" correctement l'utilisateur sur la manière d'utiliser notre chemin, en étant sur que tout ce qui doit être fait le soit au moment le plus opportun (et en gardant malgré tout une solution la plus simple possible).

    Ainsi, il pourra utiliser une boucle 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
    /* création d'un nouveau chemin */
    Chemin monChemin;
    /* plusieurs appels à add pour rajouter des "étapes" */
    for(Etape* it= monChemin.begin();it!=monChemin.end();
        ++it /* aurait pu être it=it->next() :D */ )
    {
        std::cout<<"ligne : "<<it->ligne() 
                 <<" colonne : " it->colonne()<<std::endl;
        /* pourrait prendre la forme de
       std::cout<<"ligne : "<<(*it).ligne() 
                 <<" colonne : " (*it).colonne()<<std::endl;
         
        std::cout<<"ligne : "<<it->data().ligne() 
                 <<" colonne : " it->data().colonne()<<std::endl;
        si l'opérateur -> et l'opérateur * ne sont pas définis
         */
     
    } 
    /* cela fonctionne aussi avec une boucle while */
    Etape * temp=chemin.begin();
    while(temp!=chemin.end())
    {
       /* utilisation de l'étape */
       ++temp;
    }
    En fait j'ai voulu afficher les éléments d'itinéraire ,comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void Itineraire::afficher(){
    	int v,d;
     
     
     
    	Chemin*	auxiliaire=depart;
    	cout<<"\n\n\n"<< auxiliaire->m_case.get_Ligne()<<"\n\n\n"<<endl;
    	 while(auxiliaire!=arrivee)
                {v=auxiliaire->get_case().get_Col();d=auxiliaire->get_case().get_Ligne();
    				cout<<("(")<<v<<(",")<<d<<("   ");
    				auxiliaire=auxiliaire->m_next;
    				}
    }
    C'est normal... Si j'en juge par ta structure chemin, cela ne devrait déjà pas compiler (elle ne dispose pas de la fonction membre get_case )
    or je me surpris que les valeurs des cases de départ changent dès la première utilisation de get_Ligne()!
    en notant bien que tu l'as utilisé dans ton code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      Chemin* temp=new Chemin(c);cout<<"\n\n\n"<<temp->m_case.get_Ligne()<<"\n\n\n"<<endl;
    et ça a bien marché.
    C'est aussi normal, new Chemin(c) appelle le constructeur de Chemin qui prend en paramètre... une référence constante sur un objet de type Case...

    C'est la mise en oeuvre d'un principe nommé RAII(Ressource Acquisition Is Initialisation) et dont le but est de faire en sorte que tout objet créé soit directement initialisé avec les valeurs utiles
    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
    Inscrit en
    Mai 2009
    Messages
    56
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 56
    Par défaut
    avant tout je veux dire quelque chose:
    pour moi (après avoir entendu tes conseils ):
    Etape est appelée chemin
    et Chemin est Itineraire!
    Donc Chemin aura le même code que tu as donné pour "Etape"

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Citation Envoyé par dingua Voir le message
    Vraiment,c'est génial..oui surtout d'avoir un qui explique les choses ainsi..
    Merci bien Koala!!!
    Mais si on a voulu(imposer) bien avoir "Chemin" comme structure?alors comme ça les choses deviennent plus difficiles?!
    Qu'entends tu par imposer d'avoir "chemin" comme structure

    Est-ce "uniquement" le fait d'utiliser le mot clé struct et non le mot clé class, ou est-ce le fait de n'avoir qu'une structure au sens C du terme (un simple agrégat de données n'ayant pas de fonctions membres)

    Dans le premier cas, comme je l'ai expliqué, tu peux utiliser les termes class et struct de manière strictement équivalente, du moins dans le cas présent.

    La seule différence flagrante étant la visibilité par défaut des membres (publique pour les structures, privée pour les classes).

    Dans le second cas, rien ne t'empêche d'abandonner l'idée de travailler en orienté objet, et de sortir les différentes fonctions membres de ta structures.

    En ne plaçant qu'une déclaration anticipée de la structure dans le fichier d'en-tête (en plus de la seule déclaration des fonctions) et en définissant la structure et les fonctions dans un fichier d'implémentation séparé, tu peux obtenir une structure pour laquelle la seule chose que l'utilisateur en connaisse soit... les fonctions qui permettent de manipuler cette structure (un peu à l'image du FILE en C)
    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

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

Discussions similaires

  1. Programme pour ajouter et supprimer élément à une liste
    Par basset1991 dans le forum Général Java
    Réponses: 3
    Dernier message: 15/12/2013, 23h12
  2. Ajouter un élément à une liste
    Par izulah dans le forum Prolog
    Réponses: 5
    Dernier message: 17/03/2009, 08h57
  3. Ajouter un élément à une liste
    Par circe dans le forum R
    Réponses: 2
    Dernier message: 24/10/2008, 18h00
  4. Ajout élément à une liste
    Par Parkman dans le forum InfoPath
    Réponses: 11
    Dernier message: 14/05/2008, 08h41
  5. Réponses: 22
    Dernier message: 24/11/2006, 00h36

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