Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2989 connectés 

 


 Mot :   Pseudo :  
 
 Page :   1  2  3
Auteur Sujet :

[C++ débutant] Génération d'instances dynamique (?)

n°1316892
slash33
Posté le 02-03-2006 à 12:45:21  profilanswer
 

Reprise du message précédent :

ParadoX a écrit :

[:mlc]  [:mlc] Vous êtes à bloc, dites-moi ^^


C'est le métier qui veut ça. Tu es sûr de vouloir devenir développeur ?  :whistle:


Message édité par slash33 le 02-03-2006 à 13:02:12
mood
Publicité
Posté le 02-03-2006 à 12:45:21  profilanswer
 

n°1316894
ParadoX
Posté le 02-03-2006 à 12:47:58  profilanswer
 

Pas vraiment, m'enfin on ne sait jamais :o :D


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1316896
slash33
Posté le 02-03-2006 à 12:48:34  profilanswer
 

Mon diagramme de classes
 
http://img113.imageshack.us/img113/9559/dcformesetgroupes4qx.png
 
(je précise que je suis novice en UML  :sweat: )
 
Le point d'entrée est un groupe racine (pas de groupe parent)


Message édité par slash33 le 02-03-2006 à 13:00:40

---------------
Touche pas à mon code!
n°1316964
ParadoX
Posté le 02-03-2006 à 14:03:30  profilanswer
 

Bon, j'avance avec ma fonction de recherche récursive, mais ... Elle fonctionne quand il s'agit de renvoyer des char*, mais dès que la change pour qu'elle renvoie des pointeurs sur des List::Node, ça marche plus, l'appel récursif ne se fait pas :/
 
Voyez par vous-meme:
 

Code :
  1. char* Liste::estPresentFull(char *nomRecherche, Liste &uneListe)
  2. {
  3. Iterateur monIterateur(uneListe);
  4. char *result = "Pas Trouve";
  5.     if(!estVide())
  6.     {       
  7.         while(!monIterateur.finDeListe())
  8.         {
  9.             if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0)
  10.   {         
  11.    return monIterateur.valeur()->getNom();
  12.             }
  13.             else
  14.             {
  15.                 if(strcmp(monIterateur.valeur()->getType(), "groupe" ) == 0)
  16.                 {
  17.                     Groupe *tmp =  reinterpret_cast<Groupe*> (monIterateur.valeur());  // Voir annotation après le code !
  18.                     result =  estPresentFull(nomRecherche, tmp->getMonGroupe());
  19.                 }
  20.             }
  21.             monIterateur.avance();
  22.         }
  23.     }
  24.     else
  25.     {
  26.         if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0)
  27.  {         
  28.   result =  monIterateur.valeur()->getNom();
  29.         }
  30.  monIterateur.avance();
  31.     }
  32.     return result;
  33. }


 
Tout fonctionne à tous les niveaux de hierarchie de groupes. Mais maintenant:
 

Code :
  1. Liste::Node* Liste::estPresentFull(char *nomRecherche, Liste &uneListe) const
  2. {
  3. Iterateur monIterateur(uneListe);
  4. Liste::Node *result = this->getTete();
  5.     if(!estVide())
  6.     {       
  7.         while(!monIterateur.finDeListe())
  8.         {
  9.             if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0)
  10.   {         
  11.    return monIterateur.getActuel();
  12.             }
  13.             else
  14.             {
  15.                 if(strcmp(monIterateur.valeur()->getType(), "groupe" ) == 0)
  16.                 {
  17.                     Groupe *tmp =  reinterpret_cast<Groupe*> (monIterateur.valeur());
  18.                     result =  estPresentFull(nomRecherche, tmp->getMonGroupe());
  19.                 }
  20.             }
  21.             monIterateur.avance();
  22.         }
  23.     }
  24.     else
  25.     {
  26.         if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0)
  27.  {         
  28.   result =  monIterateur.getActuel();
  29.         }
  30.  monIterateur.avance();
  31.     }
  32.     return result;
  33. }


 
Il ne me trouve plus que les résultats de 1er niveau, on dirait que l'appel récursif ne se fait pas :(
 
 
 
 
 :cry:  :cry:  :cry:  :cry:  :cry:


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1316982
franceso
Posté le 02-03-2006 à 14:20:18  profilanswer
 

ParadoX a écrit :

Code :
  1. char* Liste::estPresentFull(char *nomRecherche, Liste &uneListe)



Je réitère ma remarque : pourquoi avoir un deuxième argument de type Liste, alors que ta fonction estPresentFull est membre de la classe Liste ?
 
Encore une fois, tu as mélangé uneListe avec la liste appelante : lorsque tu crées l'itérateur, c'est bien sur uneListe, mais par contre ton test estVide() s'effectue sur la liste pointée par this
 
Pourquoi ne pas faire tout simplement :

Code :
  1. char* Liste::estPresentFull(char *nomRecherche)
  2. {
  3.   Iterateur monIterateur(this);
  4.   /*...*/
  5.   if(!estVide())
  6.   {       
  7.     /* ... */
  8.     // Appel récursif
  9.     result = tmp->getMonGroupe()->estPresentFull(nomRecherche);
  10.   }
  11. }


 

n°1317003
ParadoX
Posté le 02-03-2006 à 14:30:40  profilanswer
 

franceso a écrit :

Je réitère ma remarque : pourquoi avoir un deuxième argument de type Liste, alors que ta fonction estPresentFull est membre de la classe Liste ?
 
Encore une fois, tu as mélangé uneListe avec la liste appelante : lorsque tu crées l'itérateur, c'est bien sur uneListe, mais par contre ton test estVide() s'effectue sur la liste pointée par this
 
Pourquoi ne pas faire tout simplement :

Code :
  1. char* Liste::estPresentFull(char *nomRecherche)
  2. {
  3.   Iterateur monIterateur(this);
  4.   /*...*/
  5.   if(!estVide())
  6.   {       
  7.     /* ... */
  8.     // Appel récursif
  9.     result = tmp->getMonGroupe()->estPresentFull(nomRecherche);
  10.   }
  11. }



 
Jep c'est vrai, j'ai oublié le if(!estVide()), mais si je garde le 2eme parametre et que je mets if(!uneListe.estVide()), ça reviens à la meme chose :/


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317009
franceso
Posté le 02-03-2006 à 14:33:35  profilanswer
 

ParadoX a écrit :

Jep c'est vrai, j'ai oublié le if(!estVide()), mais si je garde le 2eme parametre et que je mets if(!uneListe.estVide()), ça reviens à la meme chose :/


 
C'est vrai, pourquoi faire simple alors qu'on peut faire compliqué ;)

n°1317013
ParadoX
Posté le 02-03-2006 à 14:35:24  profilanswer
 


Bon j'ai fait comme tu as dit, m'enfin j'ai tjrs une erreur de pointeur ... quand l'objet recherché est ds le 1er niveau, c'est bon il trouve. Sinon, paff :/


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317026
ParadoX
Posté le 02-03-2006 à 14:43:46  profilanswer
 

La réponse de mon prof par mail (jlui avais posé la meme question)
 

Citation :


Premièrement
 
Dans le else de if (!estVide()) il me parait curieux de tester quelque chose
puisque la liste est vide !
 
L'appel récursif me semble également trop direct. Il me semble plus
judicieux de demander à chaque également de se tester lui-même:
 
if(monIterateur.valeur() == nomRecherche)
...
 
Surcharger l'opérateur == avec un char * en opérande de droite
 
Si c'est un groupe vous demandez au groupe de faire le travail:
 
Groupe *tmp =  reinterpret_cast<Groupe*> (monIterateur.valeur());
... tmp->estPresentFull(nomRecherche) ...
 
A lui de se débrouiller en interne avec sa liste
 
Les appels récursifs sont ainsi cacher par des appels de méthodes qui se
débrouillent tout seul.
 
Le pbm que je vois dans votre fonction est essentiellement ici:
 
            else
            {
                if(strcmp(monIterateur.valeur()->getType(), "groupe" ) == 0)
                {
                    Groupe *tmp =  reinterpret_cast<Groupe*>
(monIterateur.valeur());
                    result =  estPresentFull(nomRecherche,
tmp->getMonGroupe());
                }
            }
 
Si la recherche dans la sous-liste aboutie comment arrêtez-vous la boucle ?
 
Il semble que continuiez la boucle ...
 
Au fait pourquoi voulez-vous aller chercher dans les groupes?
 
A+


 
Qqun m'aide à surcharger l'operateur == ?  :sweat:


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317030
chrisbk
-
Posté le 02-03-2006 à 14:46:36  profilanswer
 

google

mood
Publicité
Posté le 02-03-2006 à 14:46:36  profilanswer
 

n°1317032
franceso
Posté le 02-03-2006 à 14:47:12  profilanswer
 

Je comprends pas trop comment marche ton truc :

  • Qu'est-ce que la fonction est censée renvoyer quand elle n'a pas trouvé l'objet recherché
  • A quoi sert le bloc "else" du "if(!estVide())" : si ta liste est vide, tu ne peux rien chercher dedans
  • tu devrais tester le retour de l'appel récursif: si tu as trouvé l'objet cherché, il faut s'arrêter tout de suite

n°1317200
slash33
Posté le 02-03-2006 à 17:19:59  profilanswer
 

Heu ton prof t'a encore conseillé une solution mettant en oeuvre reinterpret_cast<> alors finalement te fais pas chier : code n'importe quoi n'importe comment pour peu que ça ressemble à du C++ et si possible que ça marche... :fou:  
 
Au fait personne n'a parlé de mon design...  :cry:

n°1317202
chrisbk
-
Posté le 02-03-2006 à 17:23:45  profilanswer
 

C'est quoi ces reinterpret cast tout laid la ? le bout de code donné par le prof, il se trouve ou ? pas dans la liste, quand meme ? [:el g]

n°1317209
franceso
Posté le 02-03-2006 à 17:30:00  profilanswer
 

slash33 a écrit :

Heu ton prof t'a encore conseillé une solution mettant en oeuvre reinterpret_cast<> alors finalement te fais pas chier : code n'importe quoi n'importe comment pour peu que ça ressemble à du C++ et si possible que ça marche... :fou:  
 
Au fait personne n'a parlé de mon design...  :cry:


 

slash33 a écrit :

Bon voilà ça me semble correct:

  • On garde ma définition de Groupe
  • Groupe hérite de Forme
  • Forme fournit une interface de manipulation partagée avec groupe ; soit sous forme de méthodes soit comme un objet compagnon. Groupe implémente sa propre version de l'interface. Ces surcharges seront equivalentes à foreach objet do objet.monOperation(les paramètres)


Je suis entièrement d'accord avec ça. Par contre, je tiens à insister sur le fait que les formes (et groupes) devraient être stockés dans une grande liste (ou plutôt hashmap) sans se soucier de la hiérarchie. Ceci simplifierait grandement la recherche d'une forme particulière et le déplacement des formes de groupe en groupe...

n°1317217
ParadoX
Posté le 02-03-2006 à 17:35:27  profilanswer
 


Le reinterpret_cast, c'est moi qui l'ai mis la. Je ne voyais pas d'autre solution pour transformer un pointeur sur un objet en pointeur sur un Groupe. Mais bon, ça marche ... et c'est mon objectif primaire. ça marche plutot bien, d'ailleurs... sauf la recherche globale récursive :/
 
Est ce que ces 2 lignes de code sont identiques ?
 

Code :
  1. result =  estPresentFull(nomRecherche, tmp->getMonGroupe());
  2. result = tmp->getMonGroupe().estPresentFull(nomRecherche, tmp->getMonGroupe());


 
Ou, autrement dit, peut-on appeller une méthode (estPresentFull) sans mettre d'instance de classe devant ?


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317232
franceso
Posté le 02-03-2006 à 17:52:21  profilanswer
 

ParadoX a écrit :

Est ce que ces 2 lignes de code sont identiques ?

Code :
  1. result =  estPresentFull(nomRecherche, tmp->getMonGroupe());
  2. result = tmp->getMonGroupe().estPresentFull(nomRecherche, tmp->getMonGroupe());


Ou, autrement dit, peut-on appeller une méthode (estPresentFull) sans mettre d'instance de classe devant ?

Tu ne peux appeler une fonction membre sans mettre d'objet devant que si la fonction en question est statique. Dans ce cas, la fonction en peut faire appel qu'à des données membres statiques, et sa valeur de retour est donc indépendante de l'instance pour laquelle tu l'appelles. L'appel de la fonction sans préciser d'instance a donc un sens. Du coup, si maliste1 et maliste2 sont deux instances de la classe Liste, les appels maliste1.foncStatique(), maliste2.foncStatique() et Liste::foncStatique() sont tous équivalents.
 
Dans ton cas, la fonction membre estPresentFull n'est pas statique, ce qui signifie que tu DOIS l'appeler pour un objet particulier, comme dans tmp->getMonGroupe().estPresentFull(...)
Si tu es dans le contexte d'une fonction membre (non statique) de la classe et que tu ne précises pas d'objet particulier, la fonction membre sera appelée pour l'objet courant this.
Dans ton cas, l'appel estPresentFull(...) est équivalent à : this->estPresentFull(...)


Message édité par franceso le 02-03-2006 à 17:55:50
n°1317235
ParadoX
Posté le 02-03-2006 à 17:54:52  profilanswer
 

Merci :)
 
Jy retourne :o


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317284
slash33
Posté le 02-03-2006 à 18:24:37  profilanswer
 

En poussant un peu, je me dis que Shape:: label doit être un discriminant de la relation d'agrégation entre Groupe et Forme. Ainsi, un groupe ne peut contenir que des groupes et formes de nom différent.  :)  
 
Le problème se pose pour assurer la même unicité de nom dans toute la hiérarchie... :??:  
 
A moins, qu'on permette un adressage hiérachisé de ce genre là :
/groupe1/groupe5/groupe1/triangle25
 
[Séquence nostalgie...]
 
Ca me rappelle un système graphique que j'ai mis au point:
 
J'en avais marre des systèmes graphiques qui ne gèrent qu'un seul repère métrique (souvent exprimé en pixels qui plus est) alors que par exemple je voulais représenter une figure ne nécessitant pas plus de 10 unités de large et 5 unités de haut - unité étant une métrique abstraite. En l'occurence, il était très compliqué et pas du tout souple d'adapter les objets graphiques à l'espace disponible à leur représentation (affichage à l'écran, sur imprimante, etc).
 
Je voulais un système s'appuyant infine sur GDI qui me permettait de manipuler des sous-ensembles graphiques combinés les uns aux autres et disposant d'un repère de coordonnées propre! L'espace disponible pour leur représentation devait être géré au mieux selon des règles de comportement définies pour chaque objet graphique !
Au besoin, je devais pouvoir afficher uniquement une vignette et ses composants graphiques.
 
L'objectif ultime : disposer d'une planche graphique qui s'adpate à la surface disponible pour sa représentation (et au sens du système de coordonnées sous-jacent) mais dont les éléments n'étaient pas figés. Bien entendu, la gestion devait être rigoureuse et supprimer un objet ou une vignette devait libérer tous les composants sous-jacents ainsi que les outils graphiques nécessaires à sa représentation (plusieurs composants graphiques pouvaient se partager un pool d'outils graphiques commun)!
 
Autre exigence: je voulais pouvoir changer dynamiquement la plage d'adressage de chaque repère et que ma représentation graphique s'adapte en conséquence!  
 
En option, chaque planche autorisait une mode "respect du ratio hauteur/largeur" et un centrage paramétrable.
 
Le principe était de gérer une superposition de planches chacune disposant de son repère métrique propre et insérée dans un planche de plus haut niveau (n'importe laquelle !) en spécifiant un rectangle exprimé dans le repère du plan englobant. En plus l'unité métrique était libre : entier, réel, date (coton a traiter celui-là), etc. Le tout permettait un rendu graphique totalement vectoriel et dynamique à la manière des IHM java. Chaque objet graphique était nommé de manière unique au niveau d'un plan  
 
A la fin, j'ai spécialisé certaines classes pour produire un présentation de graphes comportant des courbes, des axes, des graduations d'axes (plage de graduation, pas de graduation, - le tout défini dans le repère du graphique!)  
Le top, modifier les plages d'abscisses et d'ordonnées du graphe pour le voir s'adapter sans aucun effort. Hop une fonction zoom sans frais!
 
J'ai poussé le vice jusqu'à pourvoir définir un système personnalisable et extensible pour représenter les traits, les formes pleines,... Gros délire, à la fin je pouvais, en une seule instruction, peindre le fond d'une planche en vert et dessiner un rectangle à bord arrondi en rouge d'une largeur définie (dans le repère de la planche concernée)
 
Enfin, j'ai ajouté un système d'adressage hiérarchisé par nom (y compris pour les objets responsable du rendu graphique!).
 
Qu'est-ce que je me suis éclaté là-dessus. Pas long pourtant.


Message édité par slash33 le 02-03-2006 à 18:56:07
n°1317289
slash33
Posté le 02-03-2006 à 18:27:41  profilanswer
 

franceso a écrit :

Je suis entièrement d'accord avec ça. Par contre, je tiens à insister sur le fait que les formes (et groupes) devraient être stockés dans une grande liste (ou plutôt hashmap) sans se soucier de la hiérarchie. Ceci simplifierait grandement la recherche d'une forme particulière et le déplacement des formes de groupe en groupe...


Oui mais dans ce cas, tu doubles le nombre de références sur les formes et les groupes qui sont déja disponibles.

n°1317325
franceso
Posté le 02-03-2006 à 19:19:10  profilanswer
 

slash33 a écrit :

Oui mais dans ce cas, tu doubles le nombre de références sur les formes et les groupes qui sont déja disponibles.


que veux-tu dire ?

n°1317352
slash33
Posté le 02-03-2006 à 20:11:57  profilanswer
 

La classe Groupe gère, à son niveau propre, le listing des groupes et celui des formes. On peut donc énumérer tous les objets de la hiérarchie et y accéder sans risque. L'agrégation suppose que les formes sont manipulées par un groupe (à défaut par le groupe racine)
 
Le modèle se suffit donc à lui-même. L'index "à plat" que tu proposes est intéressant pour optimiser la recherche dans l'arbre. Dans le cadre d'un projet d'étude, il est peut être inutile de compliquer la réalisation.


Message édité par slash33 le 02-03-2006 à 20:37:22
n°1317507
franceso
Posté le 03-03-2006 à 00:22:30  profilanswer
 

C'est vrai que ça demanderait sûrement un gros effort de reconception. Autant garder la structure hiérarchique déjà bien avancée.
 
En tous cas, il est intéressant de voir les problèmes qui se posent à partir d'un sujet qui paraît au premier abord assez simple.
 
ParadoX > Bon courage !!!  Au fait, il est pour quand ce projet ?

n°1317508
ParadoX
Posté le 03-03-2006 à 00:28:37  profilanswer
 


Pour lundi ^^
Tout fonctionne, sauf la recherche globale récursive.  
 
Elle plante quand:  
 

  • On recherche qqch qui n'est pas dans la liste (:D)
  • On recherche un objet qui est en derniere position d'une liste


Code :
  1. // Recherche globale récursive (de merde)
  2. Objet* Liste::estPresentFull(char *nomRecherche, Liste &uneListe, bool rechSimple) const
  3. {
  4. Objet *result = NULL;
  5. bool rechercheSimple = rechSimple;
  6. Iterateur monIterateur(uneListe);
  7. if(!rechercheSimple)
  8. {
  9.  int position = uneListe.estPresent(nomRecherche);
  10.  if(position != -1)
  11.  {
  12.   rechercheSimple = true;
  13.   monIterateur.avance(position);
  14.   result =  monIterateur.getActuel()->getValeur();
  15.   return result;
  16.  }
  17.  goto suite;
  18. }
  19. else
  20. {
  21.  suite:
  22.  if(!uneListe.estVide())
  23.  {       
  24.   while(!monIterateur.finDeListe())
  25.   {
  26.    // Si le noeud recherché est l'actuel, on retourne result
  27.    if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0)
  28.    {         
  29.     result = monIterateur.valeur();
  30.     return result;
  31.    }
  32.    else
  33.    {
  34.     if(strcmp(monIterateur.valeur()->getType(), "groupe" ) == 0)
  35.     {
  36.      Groupe *tmp =  reinterpret_cast<Groupe*> (monIterateur.valeur());
  37.      if(tmp->getMonGroupe().getNbElements() == 0)
  38.      {
  39.       if(strcmp(tmp->getNom(), nomRecherche) == 0)
  40.       {
  41.        result = monIterateur.valeur();
  42.        return result;
  43.       }
  44.      }
  45.      else
  46.      {
  47.       result =  tmp->getMonGroupe().estPresentFull(nomRecherche, tmp->getMonGroupe(), true);
  48.       return result;
  49.      }
  50.     }
  51.    }
  52.    monIterateur.avance();
  53.   }
  54.  } 
  55. }
  56. }


 
Si qqun a une solution pour virer ce "goto" (la 1ere fois que j'en utilise un, c'est pratique  [:ddr555] ), je prends. Je ne veux faire la recherche "simple" qu'une seule fois, sur la liste de départ.
 
 :hello:


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317570
franceso
Posté le 03-03-2006 à 09:28:33  profilanswer
 

ParadoX a écrit :

Elle plante quand:  
 

  • On recherche qqch qui n'est pas dans la liste (:D)
  • On recherche un objet qui est en derniere position d'une liste

Pour l'instant, tu ne traites pas du tout le cas où tu ne trouves jamais l'objet. En fait, dans ce cas, ta fonction ne passe jamais par une instruction "return" et tu dois récupérer n'importe quoi en sortie (en fait, je suis surpris que ton compilo ne te donne pas de warnings)


 
En ce qui concerne les objets en dernière position, il faut voir d'un peu plus près. Comment fonctionne exactement ton finDeListe() ?
Si fin de liste renvoie true lorsque l'itérateur est placé sur le dernier élément, alors celui-ci n'est jamais parcouru dans ton while car tu fais ton iterateur.avance() à la fin de la boucle.
 
 

ParadoX a écrit :

Si qqun a une solution pour virer ce "goto" (la 1ere fois que j'en utilise un, c'est pratique  [:ddr555] ), je prends. Je ne veux faire la recherche "simple" qu'une seule fois, sur la liste de départ.

Je ne comprends pas trop ce que tu fais avec ta recherche simple.
 
Mais en tous cas, ton goto ne sert absolument à rien ici : il ne fait que demander à exécuter le bloc else dans tous les cas ... ce que tu peux aussi bien faire en sortant toutes tes instruction du bloc else:

Code :
  1. if(!rechercheSimple)
  2. {
  3.   /* ... */
  4.   // pas de goto
  5. }
  6. if(!uneListe.estVide())
  7. {
  8.   /* ... */
  9. }
  10. // on n'a pas trouvé l'élément cherché
  11. return NULL;

n°1317579
slash33
Posté le 03-03-2006 à 09:50:45  profilanswer
 

ParadoX a écrit :

Pour lundi ^^


Un rush quoi   :o  
 
A quoi sert le paramètre uneListe ? On a déja formulé une remarque dessus.
 
Quelques conseils:
- choisi un titre de méthode descriptif. J'ai été incapable de comprendre ce que faisait ta méthode en première lecture!
- il n'est pas utile de déclarer ta méthode statique (enfin je suppose que c'est l'explication au paramètre uneListe   dans le prototype de la méthode)
- avant de coder le corps de ta méthode réfléchi à l'algorithme voir pose le par écrit. Une technique consiste à mettre en commentaire dans le code, les étapes de l'algorithme et expliquer (justifier?) les instructions conditionnelles.

Code :
  1. /**
  2. * @summary Recherche une forme ou un groupe nommé dans la liste en étendant
  3. * éventuellement la recherche aux listes sous-jacentes.
  4. * @recursive
  5. * @param aName le nom de l'objet à rechercher
  6. * @param aMode le mode de recherche, voir l'énumération seekMode.
  7. * -> Préféré à un bool car plus facilement extensible.
  8. * @return l'objet trouvé dont le nom correspond ou 0 si aucun objet n'a le nom spécifié
  9. */
  10. Object* List::FindNamedObject(const char* aName, seekMode aMode) const
  11. {
  12.    Object* result = 0; // code de retour
  13.    List::Iterator listIt = List::Iterator(*this);
  14.    // le curseur listIt est positioné sur le premier élément de la liste et prêt à l'emploi.
  15.    Object* anObject; // un objet
  16.    List::Node* aNode; // un noeud
  17.    // recherche à ce niveau et aux niveaux inférieurs si le mode de recherche le permet
  18.    while (result == 0 && listIt.hasNext())
  19.    {
  20.       aNode = listIt.current();
  21.       // sécurité: aNode ne devrait pas être nul mais on teste au cas où.
  22.       // alerte le programmeur du problème
  23.       assert(aNode, "Une List contient une référence à un Node nul!" );
  24.      
  25.       if (aNode != 0)
  26.       { // noeud valide
  27.          anObject = aNode->value();
  28.          // sécurité: anObject ne devrait pas être nul mais on teste au cas où.
  29.          // alerte le programmeur du problème
  30.          assert(anObject, "Une List::Node contient une référence nulle!" );
  31.          if (anObject && strcmp(anObject->Name(), aName) == 0)
  32.          {
  33.             result = anObject; // on a trouvé un objet du nom recherché
  34.          }
  35.          else if (aMode == seekWhole && anObject->Type() == objectGroup)
  36.          {
  37.             // propager la recherche à ce noeud
  38.             result = (reinterpret_cast<Groupe*>(anObject))->List()->FindNamedObject(aName, aMode);
  39.          }
  40.       } // fin noeud valide
  41.       listIt.next(); // déplace le curseur sur le noeud suivant dans la liste
  42.   } // fin de recherche
  43.   return result;
  44. }


 
Bien sûr il te faut réajuster le code avec tes classes à toi.


Message édité par slash33 le 03-03-2006 à 11:15:57
n°1317793
ParadoX
Posté le 03-03-2006 à 14:11:27  profilanswer
 

Merci, j'ai refait l'algo de recherche, mais encore un petit truc qui cloche.
 
J'ai avancé dans la recherche récursive, elle est structurée plus logiquement. Seul probleme: quand il s'agit de "redescendre" dans la hierarchie, ça pose des problemes. Voyez vous-même:
 
Plan de maListe, dans laquelle on va effectuer les recherches:
 
+--Groupe
+------Rond2
+------Groupe2
+----------LeRond777
+--Groupe4
+------Groupe3
+----------LeTriangle
+----------LeTriangle2
+--Groupe5
+-------LePolygone
+--LeCarre
 
Code:

Code :
  1. Objet* Liste::estPresentFull(char *nomRecherche, Liste &uneListe, Liste& maListe) const
  2. {
  3. Objet *result = NULL;                   // Resultat à renvoyer
  4. Iterateur monIterateur(uneListe);   // uneListe : Liste qui va changer lors de l'appel récursif
  5. Iterateur monIterateurPrincipal(maListe);  // maListe : Liste principale, ne bouge pas
  6. if(!maListe.estVide())
  7. {       
  8.  while(!monIterateur.finDeListe())
  9.  {
  10.   if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0) // C'EST L'ACTUEL !
  11.   {         
  12.    result = monIterateur.valeur();
  13.    return result;
  14.   }
  15.   else // CE N'EST PAS L'ACTUEL
  16.   {
  17.    if(strcmp(monIterateur.valeur()->getType(), "groupe" ) != 0) // CE N'EST PAS UN GROUPE !
  18.    {
  19.     monIterateur.avance();
  20.     if(monIterateur.finDeListe())  // VOIR ANNOTATIONS EN BAS !
  21.     {
  22.      monIterateurPrincipal.avance();
  23.      Iterateur monIterateur(maListe); // cf annotations en bas, #Position
  24.      monIterateur.setPosition(monIterateurPrincipal);
  25.     }
  26.    }
  27.    else // GROUPE ! --> On cherche récursivement dedans
  28.    {
  29.     Groupe *tmp = reinterpret_cast<Groupe*> (monIterateur.valeur());
  30.     result =  tmp->getMonGroupe().estPresentFull(nomRecherche, tmp->getMonGroupe(), maListe);
  31.     return result;
  32.    }
  33.   }
  34.  }
  35.  return NULL; // Pas Trouvé !
  36. }
  37. }


Annotatiions:  
Pour la recherche, l'algo est le suivant:
 
2 Iterateurs sur la Liste, un principal et un de recherche
Tant que l'itérateur de recherche n'arrive pas en fin de liste:
- Si le noeud recherché est l'actuel, trouvé !
- Sinon:  
--> C'est un Groupe  
--> on refait une recherche dedans, en lui précisant cette fois ce groupe comme Liste
 
ou bien
 
--> C'est une Forme, 2 cas:
----> C'est la derniere forme d'une liste, auquel cas il faut "revenir dans la hierarchie" (exemple: LeRond777)
----> Ce n'est pas la derniere forme, on continue
 
L'algo trouve LeRond777, mais plus le Groupe 4 ! Alors je me suis dit qu'il faut faire revenir l'iterateur de recherche au même niveau que l'itérateur principal, puis recommencer (on se retrouve alors dans le même cas de figure qu'au début, à savoir que les 2 itérateurs sont au meme niveau)
 
Quand je mets monIterateur = monIterateurPrincipal là ou il ya "#Position" dans les commentaires du code, l'algo me trouve tous les objets jusqu'au triangle2 inclus ! Sauf qu'il plante quand il arrive au groupe 5 qu'il ne trouve plus.
 
Avez-vous une idée ? :( Je ne suis pas loin de la fin !
Désolé pour le pavé ^^


Message édité par ParadoX le 03-03-2006 à 14:11:43

---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317813
franceso
Posté le 03-03-2006 à 14:36:14  profilanswer
 

:ouch: Je comprends rien à ton algo : pourquoi as-tu besoin de deux listes (et même trois avec 'this') et deux itérateurs ?
Pourquoi as-tu besoin de gérer à la main les remontées dans la hiérarchie (alors que c'est la récursivité qui s'occuppe de ça)
Dans le cas où ta liste de départ est vide, tu ne passes toujours par aucune instruction return ... :??:
 
Bref, tout ça est bien compliqué pour pas grand chose.
 
Pourquoi ne pas faire quelque chose de plus direct, dans le genre de ça :

Code :
  1. Objet* Liste::estPresentFull(char *nomRecherche)
  2. {
  3.   Objet *result = NULL;           // Resultat à renvoyer
  4.   Iterateur monIterateur(*this);  // un seul itérateur sur la liste courante
  5.   if(estVide())
  6.     return NULL;
  7.   while(!monIterateur.finDeListe())
  8.     {
  9.       if(strcmp(monIterateur.valeur()->getNom(), nomRecherche) == 0) // C'EST L'ACTUEL !
  10.         {         
  11.           result = monIterateur.valeur();
  12.           return result;
  13.         }
  14.       else // CE N'EST PAS L'ACTUEL
  15.         {
  16.           if(strcmp(monIterateur.valeur()->getType(), "groupe" ) != 0) // C'EST UN GROUPE !
  17.             {
  18.               Groupe *tmp = reinterpret_cast<Groupe*> (monIterateur.valeur());
  19.               if( result =  tmp->getMonGroupe().estPresentFull(nomRecherche) )
  20.                 return result;
  21.             }
  22.         }
  23.       monIterateur.avance();
  24.     }
  25.   return NULL;
  26. }

n°1317816
ParadoX
Posté le 03-03-2006 à 14:42:44  profilanswer
 

Le probleme c'est que si l'objet recherché est un groupe vide !
 
Genre le groupe 2:
 
+--Groupe
+------Rond2
+------Groupe2 (vide)
+--Groupe4
+------Groupe3
+----------LeTriangle
+----------LeTriangle2
+--Groupe5
+-------LePolygone
+--LeCarre  
 
 
Je sais pas encore pkoi, mais ton code plante ^^ Jvais débugger, m'enfin ça m'étonnerait que ça soit si simple !


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317822
slash33
Posté le 03-03-2006 à 14:47:39  profilanswer
 

Mais tu te prends vraiment la tête pour rien.
 
Tu construis une méthode Liste::TrouveObjet(const char* leNom, ...)
 
De ce fait elle est utilisable pour n'importe quelle Liste donc aussi bien pour la Liste de premier niveau que la Liste gérée dans un groupe.
 
La méthode a seulement à faire ceci:
 

objetTrouve = aucun
pour chaque objet de la liste et objetTrouve == aucun
faire
  si objet.nom == nom_a_trouver alors
    objetTrouve = objet
  sinon si mode == arbrecomplet et objet est un groupe alors
      objetTrouve = ((groupe)objet).liste.TrouveObjet(nom_a_trouver)
  fin si
fin pour


Message édité par slash33 le 03-03-2006 à 14:51:58
n°1317823
franceso
Posté le 03-03-2006 à 14:48:28  profilanswer
 

ParadoX a écrit :

Le probleme c'est que si l'objet recherché est un groupe vide !


il ne devrait pas y avoir de problème avec les groupes vides : dans ce cas tmp->getMonGroupe() doit être une liste vide, et l'appel récursif de estPresentFull() doit renvoyer immédiatement NULL
 

ParadoX a écrit :

Je sais pas encore pkoi, mais ton code plante ^^ Jvais débugger, m'enfin ça m'étonnerait que ça soit si simple !


Ca veut dire quoi, "plante" ?

n°1317827
ParadoX
Posté le 03-03-2006 à 14:51:20  profilanswer
 

Le prof m'a donné un coup de pouce,  
 

Code :
  1. Objet* Liste::estPresentFull(char *nomRecherche, Liste &uneListe) const
  2. {
  3. Objet *result = NULL;
  4. Iterateur monIterateur(uneListe);
  5. while(!monIterateur.finDeListe())
  6. {
  7.  if(strcmp(monIterateur.valeur()->getNom(),nomRecherche) == 0) // C'EST L'ACTUEL !
  8.  {         
  9.   result = monIterateur.valeur();
  10.   return result;
  11.  }
  12.  else // CE N'EST PAS L'ACTUEL
  13.  {
  14.   if(strcmp(monIterateur.valeur()->getType(),"groupe" ) == 0) // GROUPE
  15.   { 
  16.    Groupe *tmp =reinterpret_cast<Groupe*> (monIterateur.valeur());
  17.    result =tmp->getMonGroupe().estPresentFull(nomRecherche, tmp->getMonGroupe());
  18.    if (result)    // si pas NULL, on a trouvé sinon on continue à chercher
  19.     return result;
  20.   }
  21.  }
  22.  monIterateur.avance();
  23. }
  24. return NULL; // Pas Trouvé !


 
ça marche maintenant. C'était le  
 

Code :
  1. if (result)


 
que j'avais jamais mis :/
 
Merci beacoup à tous :) :) :) :)
La semaine prochaine je vous dirai la note qu'on a eu :o ^^
 
 :hello:


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317829
slash33
Posté le 03-03-2006 à 14:52:41  profilanswer
 

Ce code est une horreur. Simple avis personnel.

n°1317832
ParadoX
Posté le 03-03-2006 à 14:54:49  profilanswer
 

Pkoi ? :sweat:  
 
N'oubliez pas que vous autres programmeurs voyez ça d'un autre angle que moi, et qu'avec le recul que vous avez ça peut vous choquer. Pour moi, aucun pas n'est injustifié dans ce code :( :/


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317833
franceso
Posté le 03-03-2006 à 14:57:00  profilanswer
 

slash33 a écrit :

Ce code est une horreur. Simple avis personnel.


+1
 
 
Pour commencer, je n'arrive toujours pas à comprendre pourquoi tu fais une méthode statique avec 2 arguments alors que le seul argument devrait être l'étiquette à rechercher, et la seule liste impliquée dans l'affaire est this.


Message édité par franceso le 03-03-2006 à 14:58:09
n°1317834
slash33
Posté le 03-03-2006 à 14:57:54  profilanswer
 

Tu n'as pas vu le code que je t'ai proposé alors.
http://forum.hardware.fr/hardwaref [...] m#t1317579
 
Combien vois tu de return ? As tu du mal à lire le code et comprendre l'algorithme ?

n°1317840
ParadoX
Posté le 03-03-2006 à 15:02:33  profilanswer
 


C'est pourtant le prof qui m'a dit (mot pour mot, dans son mail) :
 

Citation :

Pour moi voilà comment elle devrait être écrite:


 
Le coup des return multiples, etc ... c'est une question de point de vue. La philo de notre prof c'est "Moi je fais du c++, pas de l'algo" !
Alors c'est peut-être à l'encontre de vos idées (et de la plupart des programmeurs [:spamafote]), mais moi on m'apprends comme ça cette année. Et c'est la première année ou je fais vraiment du C / C++.
 
Je vais néanmoins essayer de modifier la fonction pour n'avoir qu'un seul return et de ne lui donner qu'un char* comme parametre, si vous dites que c'est moche / pas utile ce n'est certainenement pas injustifié. Il faut juste se mettre à ma place aussi :)
 
Merci pour toutes vos aides, je n'y serais probablement pas arrivé sans tout ça, et je vais quand meme revoir ce que vous m'avez conseillé  
 
 :hello:


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317843
slash33
Posté le 03-03-2006 à 15:07:45  profilanswer
 

Faire du C++ n'interdit pas d'apprendre les pratiques à éviter.
 
La multiplication des return et des goto est néfaste au programme sauf pour une utilisation justifiée.
 
Si ton prof dit vous apprendre à faire du C++ sans vous avoir enseigné les rudiments de l'algorithmie, il fait fausse route. En théorie tu commences par concevoir l'algorithme avant de coder.
 
N'oublies pas que la lisibilité de ton programme est aussi importante que le bon fonctionnement de celui-ci. Si un jour tu es amené à utiliser ou maintenir un système que tu n'as pas créé, ais une pensée pour moi.

Message cité 2 fois
Message édité par slash33 le 03-03-2006 à 15:13:33
n°1317852
chrisbk
-
Posté le 03-03-2006 à 15:14:46  profilanswer
 

slash33 a écrit :


La multiplication des return et des goto est néfaste au programme sauf pour une utilisation justifiée.


 
pour les return, je proteste.
 
je prefere largement un truc genre
 

Code :
  1. if (!bidule)
  2.    return;
  3. ...


a  

Code :
  1. if (bidule)
  2. {
  3. }


 
 

n°1317862
franceso
Posté le 03-03-2006 à 15:31:57  profilanswer
 

Je suis plutôt de l'avis de chrisbk : il me paraît assez lisible d'évacuer les cas faciles avec des 'return'.
 
Ce qui me gêne dans le code de ParadoX, c'est plutôt le reinterpret_cast et la signature de la méthode.
 
 

slash33 a écrit :

N'oublies pas que la lisibilité de ton programme est aussi importante que le bon fonctionnement de celui-ci. Si un jour tu es amené à utiliser ou maintenir un système que tu n'as pas créé, ais une pensée pour moi.


Et pense à moi aussi :cry:

n°1317889
ParadoX
Posté le 03-03-2006 à 15:47:39  profilanswer
 

La signature est corrigée, un seul *this suffit effectivement :)
Les return, j'ai laissé ... autant dans une fonction "normale" je l'aurait corrigé, mais dans une fonction récursive c'est moins facile :/
 
Enfin, le reinterpret_cast, je n'ai pas trop le choix, cf le design de mes classes !
 
:)


---------------
Pier noir la mèr - La chanson par HFR Band - Topic TrueCrypt
n°1317909
slash33
Posté le 03-03-2006 à 16:03:59  profilanswer
 

franceso a écrit :

Je suis plutôt de l'avis de chrisbk : il me paraît assez lisible d'évacuer les cas faciles avec des 'return'.


Oui mais il s'agit du "cas particulier" que j'évoquais, c'est à dire quand cela facilite la lecture.
 
Je suis un habitué du  
 

Code :
  1. if (uneConditionFoireuse)
  2. return false;
  3. else if (uneAutreConditionFoireuse)
  4. return false;
  5. // .. fait plein d'opérations qui de toute façon n'échoueront jamais
  6. // tout à bien marché!
  7. return true;


 
Mais les return dans les boucles ben je ne le sens pas (et ça peut compliquer le debuggage)
 
Deux écoles s'opposent sur cette question, il me semble.

Message cité 1 fois
Message édité par slash33 le 03-03-2006 à 16:06:00
mood
Publicité
Posté le   profilanswer
 

 Page :   1  2  3

Aller à :
Ajouter une réponse
 

Sujets relatifs
[Résolu][Html/Javascript] Liens dans menu déroulant dynamiquerendre un menu dynamique et non statique
[Resolu]selection de ligne d'un tableau dynamique et formulaire[débutant inside] probleme lors de la construction d'un jeu de cartes.
[C++ débutant] Tester si un Objet est d'un type précis ?[MFC] Menu dynamique
[debutant C++] [Urgent] Tableau 2D nombre de colonne inconnu[débutant] char* + char* = concaténer
[URGENT] [C++ débutant] problème avec tableau a plusieurs dimensionstableau dynamique croisée
Plus de sujets relatifs à : [C++ débutant] Génération d'instances dynamique (?)


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR