Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème de structure

Sujet résolu
    3 juillet 2007 à 0:28:46

    Bonjour !

    Je suis en train de créer mon premier programme orienté objet :D mais j'ai un problème (qui est à mon avis plus de C que du C++ mais bon ...)

    Je déclare une structure "coord" dans main.h que l'inclue en haut du programme principale.
    J'utilise cette structure dans une classe, mais elle n'est pas reconnue ...

    Pouvez-vous l'aidez ??
    Voila mon code :

    // MAIN.H

    typedef struct coord coord;
    struct coord
    {
        long x;
        long y;
    };
     



    // MAIN.CPP

    #include <iostream>
    #include <string>
    #include "main.h"
    #include "Player.h"

    using namespace std;

    int main()
    {
        // Création du joueur
        Player Black("Black Templar", "The Black Ship");
       
        string namePlayer = Black.m_getName();
        string nameShip = Black.m_getShipName();
        int fuelShip = Black.m_getShipFuel();
        cout << "Player : " << namePlayer << endl;
        cout << "Ship : " << nameShip << endl;
        cout << "Fuel : " << fuelShip << endl;

            system("PAUSE");
        return 0;
    }
     



    // PLAYER.H
    #ifndef DEF_PLAYER
    #define DEF_PLAYER

    #include "Ship.h"

    class Player
    {
        public:

            Player(std::string name = "Player", std::string nameShip = "Ship");
        std::string m_getName();
        std::string m_getShipName();
        int m_getShipFuel();

        private:

        std::string a_name;
        Ship a_Ship;
    };

    #endif
     



    // PLAYER.CPP
    #include <iostream>
    #include <string>
    #include "Player.h"

    using namespace std;

    Player::Player(string name, string nameShip) : a_name(name), a_Ship(nameShip)
    {
    }

    string Player::m_getName()
    {
        return a_name;
    }

    string Player::m_getShipName()
    {
        return a_Ship.m_getName();
    }

    int Player::m_getShipFuel()
    {
        return a_Ship.m_getFuel();
    }
     



    // SHIP.H
    #ifndef DEF_SHIP
    #define DEF_SHIP

    class Ship
    {
        public:

            Ship(std::string nameShip = "Ship");
        std::string m_getName();
        int m_getFuel();
        void m_turnLeft();
        void m_turnRight();
        void m_avance();
        void m_freine();

        private:

        std::string a_name;
        int a_fuel;
        coord a_position;
        coord a_vitesse;
    };

    #endif
     



    // SHIP.CPP
    #include <iostream>
    #include <string>
    #include "Ship.h"

    using namespace std;

    Ship::Ship(string name) : a_name(name), a_fuel(100)
    {
    }

    string Ship::m_getName()
    {
        return a_name;
    }

    int Ship::m_getFuel()
    {
            return a_fuel;
    }

    void Ship::m_turnLeft()
    {
            
    }
            
    void Ship::m_turnRight()
    {
    }

    void Ship::m_avance()
    {
    }

    void Ship::m_freine()
    {
    }
     


    Voila les messages d'erreurs ...

    Ligne 3 : Player.h:4, from Player.cpp | In file inclued from Player.h:4, from Player.cpp
    Ligne 3 : Player.cpp | from Player.cpp
    Ligne 20 : Ship.h | 'coord' does not name a type
    Ligne 21 : Ship.h | 'coord' does not name a type
    [Build Error] etc...
    • Partager sur Facebook
    • Partager sur Twitter
      3 juillet 2007 à 0:45:45

      Dégages le typedef, il ne sert à rien.
      Ensuite comment veux-tu que shp.h connaisse le contenu de main.h si tu ne l'inclues pas avant ?

      PS: n'oublie pas les gardes anti-réinclusion
      PPS: en effet, aucun rapport direct avec le C++, c'est un problème d'organisation.
      • Partager sur Facebook
      • Partager sur Twitter
      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
        3 juillet 2007 à 1:01:25

        Arf... En effet, j'ai oublié d'inclure main.h dans Ship.h ... J'ai cru qu'une seule fois suffisait ...

        Voila le nouveau code de main.h et Ship.h

        // MAIN.H
        #ifndef DEF_MAIN
        #define DEF_MAIN

        struct coord
        {
            long x;
            long y;
        };

        #endif
         



        // SHIP.H
        #ifndef DEF_SHIP
        #define DEF_SHIP

        #include "main.h"

        class Ship
        {
            public:

                Ship(std::string nameShip = "Ship");
            std::string m_getName();
            int m_getFuel();
            void m_turnLeft();
            void m_turnRight();
            void m_avance();
            void m_freine();

            private:

            std::string a_name;
            int a_fuel;
            coord a_position;
            coord a_vitesse;
        };

        #endif
         



        Par contre j'ai encore des questions :
        Pourquoi le deftype n'est-il plus obligatoire ?? C'est une nouveauté du C++ ??

        Ensuite, j'ai essayé d'initialisé les variables de la structure lors de la création d'un objet, mais ça plante à la compilation ...
        Voila le constructeur de Ship :
        Ship::Ship(string name) : a_name(name), a_fuel(100), a_position.x(0), a_position.y(0), a_vitesse.x(5), a_vitesse.y(5)
        {                             
        }


        en utilisant juste Ship::Ship(string name) : a_name(name), a_fuel(100) ça marche nickel, mais dès que j'y introduit les structures ... bug !
        • Partager sur Facebook
        • Partager sur Twitter
          3 juillet 2007 à 1:26:58

          Ce n'est pas une nouveauté mais dès que tu déclares une struct, tu crées un objet (ou une variable complexe) donc, le typedef ne t'es pas utile, puisque le typedef sert en grande partie a renommer une variable.

          avec ta déclaration de typedef, tu te retrouvais a dire "remplace tous les struct coord par coord"

          ensuite, si tu essaies de faire de l'objets, je te conseillerais vivement d'utiliser un constructeur, plustot que d'initialiser tes variables dans ton pre-constructeur, c'est beaucoup plus propre/lisible/mieu :p .
          De plus je te recommande vivement d'utiliser des accesseurs et des mutateurs pour modifier l'état de ta variable. De cette manière, ton programme respecterait beaucoup mieu les normes de l'encapsulation.

          Edit: ajouter 2 ou 3 commentaire ...
          • Partager sur Facebook
          • Partager sur Twitter
            3 juillet 2007 à 12:05:40

            Merci pour les explications !

            Je ne comprend pas ce que tu entend pas pré-constructeur et constructeur ?

            Le pré constructeur, c'est les variables avant l'acollade et le constructeur, c'est après ?? non ?

            Dans ces cas là, le problème avec le constructeur de Player, c'est que je doit définir une classe et ça me fait tout planté lors de l'exécution (j'ai le droit à la beep musique ^^)

            Voila ce qui bug
            Player::Player(string name, string nameShip)  // Constructeur
            {
                a_name = name;
                a_Ship = nameShip;
                cout << "EVENT : Player object \"" << a_name << "\" has been created" << endl;
            }


            Par contre comme ça, ça ne bug plus :
            Player::Player(string name, string nameShip) : a_Ship(nameShip) // Constructeur
            {
                a_name = name;
                cout << "EVENT : Player object \"" << a_name << "\" has been created" << endl;
            }



            Pour ce qui est des structure j'ai réussi à les initialisé dans le constructeur comme cela :
            Ship::Ship(string name) // Constructeur
            {       
                    a_name = name;
                    a_fuel = 100;
                    a_position.x = 0;
                    a_position.y = 0;
                    a_vitesse.x = 5;
                    a_vitesse.y = 5;
                cout << "EVENT : Ship object \"" << a_name << "\" has been created" << endl;                          
            }



            Enfin, pour ce qui est des assesseurs et mutateur, je vais laisser tombé pour le moment, je les étudierais dans 2 jours, le temps de finir ce programme. Sinon je vais tout mélanger !! J'ai commencé à lire le tuto sur le C++ il y a 2 jours seulement (et j'ai fini les chapitres sur les classes)


            Merci pour ton aide :)
            • Partager sur Facebook
            • Partager sur Twitter
              4 juillet 2007 à 6:27:43

              C'est tout a fait normal que ça bug puisque aShip n'est pas une string mais un objet, alors, lorsque tu dis
              aShip=NameShip
              tu te retrouves a lui dire de mettre une string dans un objet complexe, ce qui est assez bizarre pour lui (meme si une construction implicite aurait du se produire a mon avis, mais bon...) alors que quand tu dis
              aShip(NameShip)
              tu appelles le constructeur de Ship qui lui recoit une string.

              PS: J'aimerais te dire que je n'ai pas pris le temps de me plonger a fond dans ton code, mais a premiere vu, c'est ce que je vois. Quelqu'un corrigez moi si je dis des conneries.

              deuxieme chose:

              lorsque tu tapes


              /*ici, c'est le constucteur*/
              UneClasse::UnConstructeur( ... )
              :/*ici c'est le préconstructeur*/
              {
              /*ici tu innitiallises tes variables pour t'assurer que l'objet aura un état valide a la fin de la construction*/
              }
               
              • Partager sur Facebook
              • Partager sur Twitter
                4 juillet 2007 à 12:52:38

                Oui, c'est ce que j'ai fait au début, mais il me met une jolie erreur de compilation :(

                Player::Player(string name, string nameShip) // Constructeur
                {
                    a_name = name;
                    a_Ship(nameShip);
                    cout << "EVENT : Player object \"" << a_name << "\" has been created" << endl;
                }


                no match for call to '(Ship)(std::string&amp;)'



                Enfin, j'ai une dernière petite erreur, lorsque je ferme mon programme, j'apelle le deconstructeur mais ça me plante le programme (lorsque je ferme la fenetre)

                // Libère la mémoire
                    Player[0].~Player();        // Détruit l'objet
                    TTF_CloseFont(police);      // Libère la police
                    TTF_Quit();    // Ferme la biblio texte
                    SDL_Quit();    // Ferme SDL

                    return EXIT_SUCCESS;        // Fin du programme
                 
                • Partager sur Facebook
                • Partager sur Twitter
                  4 juillet 2007 à 13:11:39

                  Ce n'est pas à toi d'appeler le destructeur. L'appel se fait automatiquement lorsque la variable est détruite à la fin du bloc courant.

                  Si par contre tu crées ton objet via un new, il faudra un delete, qui lui appellera le destructeur.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
                    5 juillet 2007 à 1:09:28

                    d'accord merci :)
                    Je file voir le chapitre sur l'allocation dynamique d'objet alors !!


                    Personne n'a d'idée pour le constructeur ??
                    • Partager sur Facebook
                    • Partager sur Twitter
                      5 juillet 2007 à 1:20:08

                      Sans savoir d'où sort le a_Ship, non.

                      PS: tes conventions de nommages sont super exotiques.
                      • Partager sur Facebook
                      • Partager sur Twitter
                      C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                        5 juillet 2007 à 8:38:51

                        Citation : Black Templar


                        Ensuite, j'ai essayé d'initialisé les variables de la structure lors de la création d'un objet, mais ça plante à la compilation ...
                        Voila le constructeur de Ship :

                        Ship::Ship(string name) : a_name(name), a_fuel(100), a_position.x(0), a_position.y(0), a_vitesse.x(5), a_vitesse.y(5)
                        {                             
                        }



                        en utilisant juste Ship::Ship(string name) : a_name(name), a_fuel(100) ça marche nickel, mais dès que j'y introduit les structures ... bug !



                        En C++ une structure est une classe, la seule différence réside dans l'accessibilité par défaut (public pour struct, private pour class), ce qui signifie que tu peux doter les structures de méthodes donc leur définir des constructeur.


                        struct coord
                        {
                            int m_x;
                            int m_y;

                            coord():m_x(0),m_y(0){}; // initialise la structure à 0

                            coord(int x,int y):m_x(x),m_y(y){}; // affecte des valeurs de coordonnées

                            coord(const coord & src) // constructeur de copie
                            {
                                m_x = src.m_x;
                                m_y = src.m_y;
                            }

                        }
                         


                        Ensuite si tu n'as pas besoin d'une coordonnée particulière pour créer ta classe Ship, tu ne mets rien sur les coord dans le constructeur de ta classe Ship, ainsi c'est le constructeur sans arguments qui sera appelé, tes classes Ship seront toujours construites avec des coord {0,0}, si tu as besoin de créer avec des coord différentes il te suffit de modifier ton constructeur de Ship par exemple


                        // Crée un Ship avec une position (0,0) et une vitesse (0,0)
                        Ship::Ship(const std::string & name)
                        :a_name(name),a_fuel(100)
                        {
                        }

                        // Crée un ship  avec une position passée en paramètre et une vitesse (0,0)
                        Ship::Ship(const std::string & name, const coord & position)
                        :a_name(name),a_fuel(100),a_position(position)
                        {
                        }

                         
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                          6 juillet 2007 à 16:49:36

                          Merci pour tes infos int21h !


                          Citation : lmghs

                          PS: tes conventions de nommages sont super exotiques.


                          Bah, il faut bien que je m'y retrouve dans mon programme ! ^^
                          a_ pour les attributs d'une classe
                          m_ pour les méthodes
                          une majuscule pour une classe ou un objet ;)

                          C'est pas très exotique je trouve !


                          Sinon, pourquoi ne puis-je pas faire ça :

                          Player::Player(string name, string nameShip) // Constructeur
                          {
                              a_name = name;
                              a_Ship(nameShip);
                              cout << "EVENT : Player object \"" << a_name << "\" has been created" << endl;
                          }


                          Il bug sur a_Ship(nameShip);

                          D'après mes convention on peut dire que a_Ship est à la fois un attribut et un Objet donc c'est un objet apellé à partir d'une classe ;)


                          Pour avoir la source complete, voir ici : http://infoprog.keo.in/Black_Templar/prgmPOO.rar
                          Vous devez avoir installé SDL SDL_ttf et SDL_gfx
                          ++
                          • Partager sur Facebook
                          • Partager sur Twitter
                            6 juillet 2007 à 17:50:03

                            Il faut que tu mettes ton initialisation dans la liste d'initialisation


                            Player::Player(string name, string nameShip) // Constructeur
                            :a_Ship(nameShip),a_name(name)
                            {
                                cout << "EVENT : Player object \"" << a_name << "\" has been created" << endl;
                            }
                             


                            Autre conseil, évite les signatures de fonction du genre


                            void fonction(std::string aString);
                             


                            Ce type de fonction est très inefficace, car lors de l'appel, le programme fait une copie de l'objet string sur la pile. Si ta string contient un texte de 500 pages, bonjour les performances de ta fonction!

                            Tu as 3 possibilités pour passer ta chaîne, une dans laquelle tu interdit la modification de la chaine et deux dans laquelle tu l'autorise.

                            Les méthodes avec modification autorisées:

                            D'abord la bonne vielle méthode C qui consiste à passer par un pointeur


                            void fonction(std::string * pString)
                            {
                               *pString += "toto fait du velo";
                            }
                             


                            La méthode plus typée C++ qui consiste à passer par référence


                            void fonction(std::string & String)
                            {
                               String += "toto fait du velo";
                            }
                             


                            Enfin par référence constante, dans cette méthode tu indiques au compilateur que tu ne vas pas modifier le paramètre


                            void fonction(const std::string & String)
                            {
                               std::string temp = String;
                               temp += "toto fait du velo";

                               // Pas de modification de la string originale
                               // je travaille sur une copie
                            }
                             


                            Quand tu passes tes paramètres par référence ou par adresse tu ne copies pas l'objet, tu délivres un pointeur sur l'objet original, ainsi que ta string soit vide ou qu'elle contienne l'annuaire de l'Ile de France, l'appel de fonction se fera à la même vitesse (évidemment le traitement derrière ne prendra pas forcément le même temps).

                            Dans le cas de tes constructeurs je passerais les chaînes de caractères par références constante, car tu ne les modifieras jamais dans les constructeurs.

                            Player::Player(const std::string & name, const std::string & nameShip) // Constructeur
                            :a_Ship(nameShip),a_name(name)
                            {
                                std::cout << "EVENT : Player object \"" << a_name << "\" has been created" << std::endl;
                            }
                             




                            • Partager sur Facebook
                            • Partager sur Twitter
                            Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
                              6 juillet 2007 à 23:18:15

                              Citation : Black Templar

                              Citation : lmghs

                              PS: tes conventions de nommages sont super exotiques.


                              Bah, il faut bien que je m'y retrouve dans mon programme ! ^^
                              a_ pour les attributs d'une classe
                              m_ pour les méthodes
                              une majuscule pour une classe ou un objet ;)

                              C'est pas très exotique je trouve !


                              Quand les grosses conventions qui occupent bien 95% des codes existants sont :
                              - m_name pour les variables membre ; rien pour les fonctions membre
                              - myName pour les variables membre ; rien pour les fonctions membre
                              - name_ pour les variables membre ; rien pour les fonctions membre

                              Et parfois
                              - aName pour les paramètres

                              Si, je t'assure, c'est exotique. :p


                              Sinon, oubliez les références non constantes et les pointeurs pour ce genre de trucs. Il ne permettent pas les convertions implicites et autres temporaires non nommés issus de retours de fonctions comme l'opérateur de concaténation.
                              • Partager sur Facebook
                              • Partager sur Twitter
                              C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.

                              Problème de structure

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                              • Editeur
                              • Markdown