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 :

[exercice] Donnez-moi vos avis sur mon code


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut [exercice] Donnez-moi vos avis sur mon code
    Bonjour tout le monde !

    Je connais les bases principales du C++, c'est-à-dire : les bases, les classes, le polymorphisme, la surcharge d'opérateur (et de n'importe quelle fonction), les pointeurs (là-dessus, j'ai peu d'expérience), attributs et méthodes statiques, l'amitié (peu d'expérience la-dessus aussi)...
    ainsi qu'un peu le C : bases, chaînes de caractères, énumérations, structures, un peu d'allocation dynamique....
    Mais je n'ai quand même pas un très bon niveau (enfin, je ne pense pas).

    Bref, j'en viens à que je cherchais à m'entraîner et j'ai trouvé des exercices qui sont pas trop mals (sur les classes en tout cas), et j'ai commencé le premier en ajoutant des choses, pour utiliser l'héritage, le polymorphisme, la surcharge d'opérateur.


    Je mets le code ici :
    4 parties :
    - les main :
    main.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #ifndef MAIN_H_INCLUDED
      #define MAIN_H_INCLUDED
     
      #include <iostream>
      #include "Rectangle.h"
      #include "Carre.h"
     
    #endif // MAIN_H_INCLUDED
    main.cpp :
    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
     
    #include "main.h"
     
    using namespace std;
     
    void UtFormes()
    {
        Rectangle R1(2, 3);
        Carre C1 = 5;
     
        cout << C1;
     
        cout << R1;
    }
     
    int main()
    {
        UtFormes();  // Exercice 1 sur les rectangles (que j'ai approfondi)
     
        return 0;
    }
    - Formes :
    Forme.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #ifndef FORME_H
      #define FORME_H
     
    struct Forme
    {
        virtual float perimetre() { return 0; }
        virtual float aire() { return 0; }
    };
     
    #endif // FORME_H
    - Rectangles :
    Rectangles.h :
    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
     
    #ifndef RECTANGLES_H_INCLUDED
      #define RECTANGLES_H_INCLUDED
     
    #include <iostream>
    #include <cstdlib>
    #include "Forme.h"
     
    class Rectangle : public Forme
    {
        public:
     
            Rectangle(const float& Largeur = 0, const float& Longueur = 0);
     
            virtual float perimetre() const { return 2*(m_larg + m_long); }  // ou 2*m_larg + 2*m_long
            virtual float aire() const { return m_larg * m_long; }
     
            void changerLongeurs(const float& Largeur, const float& Longueur) { m_larg = Largeur, m_long = Longueur; }
            float&  largeur() { return m_larg; }
            float&  longueur() { return m_long; }
            float   largeur() const { return m_larg; }
            float   longueur() const { return m_long; }
     
            friend std::ostream& operator<<(std::ostream& o, const Rectangle& r);
     
        private:
     
            float m_larg, m_long;
    };
     
    std::ostream& operator<<(std::ostream& o, const Rectangle& r);
     
    #endif // RECTANGLES_H_INCLUDED
    Rectangles.cpp :
    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
     
    #include "Rectangle.h"
     
    using namespace std;
     
    Rectangle::Rectangle(const float& Largeur, const float& Longueur)
             : m_larg(Largeur), m_long(Longueur)
    {}
     
    ostream& operator<<(ostream& o, const Rectangle& r)
    {
        o << "Rectangle de largeur " << r.m_larg << " et de longueur " << r.m_long << ".\nSon aire et son perimetre sont donc respectivement " << r.aire() << " et " << r.perimetre() << '.' << endl;
     
        return o;
    }
    - Carrés :
    Carres.h :
    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
     
    #ifndef CARRES_H
      #define CARRES_H
     
    #include <iostream>
    #include <cstdlib>
    #include "Forme.h"
     
    class Carre : public Forme
    {
        public:
     
            Carre(const float& Cote = 0);
     
            virtual float perimetre() const { return m_cote*4; }
            virtual float aire() const { return m_cote*m_cote; }
     
            float&  cote() { return m_cote; }
            float   cote() const { return m_cote; }
     
            friend std::ostream& operator<<(std::ostream& o, const Carre& c);
     
        private:
     
            float m_cote;
    };
     
    std::ostream& operator<<(std::ostream& o, const Carre& c);
     
    #endif // CARRES_H
    Carres.cpp :
    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
     
    #include "Carre.h"
     
    using namespace std;
     
    Carre::Carre(const float& Cote)
         : m_cote(Cote)
    {}
     
    ostream& operator<<(ostream& o, const Carre& c)
    {
        o << "Carre de cote " << c.m_cote << ".\nSon aire et son perimetre sont donc respectivement " << c.aire() << " et " << c.perimetre() << '.' << endl;
     
        return o;
    }
    Si vous voulez, je peux poster le projet entier sous zip pour Code::Blocks (Windows), comme ça, ça vous évitera de faire du copier-coller si vous voulez compiler (enfin, pour ceux qu'utilisent Code::Blocks sous Windows).

    Sortie :

    http://www.mediafire.com/i/?gm1ty49dwj7cls7

    Avant d'attaquer l'exercice sur les piles, j'aimerais faire une classe Cercle, mais je ne surchargerais pas l'opérateur d'injection, parce que dessiner un cercle, ça demande de travailler les équations que je viens de voir en maths, et bon... en console... heu... bref ! Je ne vais pas le surcharger. En SDL (ou en SFML, quand je serais allé la voir), je tenterais volontiers un jour.

    Voilà, merci d'avance à tous ceux qui me feront avancer

    Dernière édition du code : le 17/05/2012 à 13h43

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 211
    Points
    23 211
    Par défaut
    Pas de code exécutable dans un .h ! (Sauf avec les templates mais là c'est une autre histoire)

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    Ah ? heu, bonjour !

    D'accord, c'est un peu... concis comme façon.
    Ok, je modifie le code.

    Mais sinon, pas d'autres commentaires ?
    Par exemple, qu'est-ce qui est habile/maladroit, simplifiable, bien/mal pensé...
    Qu'est-ce que tu (ou tout le monde) trouves bien fait, à refaire, etc... ?

    Merci d'avance.

  4. #4
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 211
    Points
    23 211
    Par défaut
    Pourquoi des static ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    static float perimetreDe(const Forme& forme) { return forme.perimetre(); };
    static float aireDe(const Forme& forme) { return forme.aire(); };
    Une méthode virtuelle serait mieux je pense.

    Sinon, pour l'affichage, tu peux redéfinir l'opérateur<<


    Tu peux aussi définir ta fonction d'affichage dans la classe mère.

  5. #5
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Neckara: Il est parfaitement possible de mettre une fonction inline !

    Sinon, en lecture superficielle, je remarque la présence de mélanges de struct et de class ; ainsi qu'un attribut statique public (m_nbrFormes). Ce qui est très déconseillé. Attribut public, la norme s'habitue à dire que c'est le mal, même si des fois ça peut avoir sa raison d'être. Pas ici. Attribut statique, c'est en général très mauvais pour (plus tard) le multi-thread. Donc, en général, il faut éviter.

    Aussi, la présence de m_larg et m_long en protected. Que devrait en faire une classe héritante ?

    Aussi, la méthode afficheTout, méthode horrible par excellence, qui me révulse à chaque fois que je la vois. (Oui, je vais mieux maintenant, merci.)

    Aussi, l'implémentation de ostream << Rectangle est ... originale ? (Pourquoi 177 ?)

    Enfin, je dirais qu'il y a peut-être une sur-représentation des fonctions virtuelles publiques. Voir peut-être NVI (Non Virtual Interface), qui pourrait être avantageux.

    Voilà, je pense que c'est tout !

  6. #6
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 211
    Points
    23 211
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Neckara: Il est parfaitement possible de mettre une fonction inline !
    ?? Je n'ai jamais dit qu'on ne peut pas définir de fonctions inline.

    Citation Envoyé par Ekleog Voir le message
    Enfin, je dirais qu'il y a peut-être une sur-représentation des fonctions virtuelles publiques. Voir peut-être NVI (Non Virtual Interface), qui pourrait être avantageux.
    Je ne connaissais pas^^

    http://cpp.developpez.com/faq/cpp/?p...e#HERITAGE_NVI

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Sinon, en lecture superficielle, je remarque la présence de mélanges de struct et de class
    En quoi cela est-il un problème ?

  8. #8
    Membre averti
    Avatar de David Fleury
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 253
    Points : 307
    Points
    307
    Par défaut
    Il ne manquerait pas des constructeurs par copie, et des opérateur d'affectations ? (pour éviter des bugs sur les compteurs de nombres de forms, ...)

  9. #9
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Dans UtFormes(), les instanciations dynamiques de tes formes (via new/delete) sont inutiles. Un Rectangle r1(2, 3); serait plus simple et plus approprié.

    Je suis d'accord avec Ekleog pour afficheTout (sachant bien que tu ne fais que reprendre l'exemple du wiki, tu n'y peux rien). Et c'est peut-être plus important que le reste : A quoi sert un Rectangle ? A contenir/traiter/restituer des valeurs géométriques. L'affichage (donc la partie IHM) n'est pas de sa responsabilité. C'est une classe différente qui doit se charger de l'IHM (aussi minimale soit-elle) à partir de Formes qu'on lui fournira.

  10. #10
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Bonjour,

    Y a-t'il un intérêt à avoir un header pour le main.cpp ?
    Nullius in verba

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    Alors,

    d'abord, merci pour toutes vos réponses.
    Ensuite, j'insisterais sur le fait que j'ai peu d'expérience, et que je ne comprends pas tout, et que tout ce que je connais, c'est par le biais de tutos, je n'ai jamais eu une personne expérimenté derrière moi pour me corriger (sauf avec les forums, mais je ne faisais jamais comme ici, où le code est fonctionnel).

    @ Eckara :
    Sinon, pour l'affichage, tu peux redéfinir l'opérateur<<
    J'ai choisie de faire deux affichages différents, un qui fait le maximum, et un autre qui ne fait que le "dessiner". Mais apparemment, cette fonctionnalité est mal placée, je ne vais garder que la surcharge de l'opérateur, et j'afficherais seulement les infos (aire, périmètre, largeur...).
    Tu peux aussi définir ta fonction d'affichage dans la classe mère.
    La surcharge d'opérateur ou la méthode 'afficheTout()' ? si la surcharge d'opérateur, je ne vois pas trop cmment, si 'afficheTout()', le problème est déjà réglé.

    Sinon, en lecture superficielle, je remarque la présence de mélanges de struct et de class
    J'ai définis la 1ere comme struct pour la raison indiqué en commentaire.
    Maintenant, à tout le monde : Dois-je changer en class ?

    ainsi qu'un attribut statique public (m_nbrFormes). Ce qui est très déconseillé. Attribut public, la norme s'habitue à dire que c'est le mal, même si des fois ça peut avoir sa raison d'être. Pas ici. Attribut statique, c'est en général très mauvais pour (plus tard) le multi-thread. Donc, en général, il faut éviter.
    Pour le nombre de formes, j'aimerais que vous m'aidiez à le faire intelligemment et dans les conventions.

    Aussi, la présence de m_larg et m_long en protected. Que devrait en faire une classe héritante ?
    Je ne sais pas trop pourquoi il sont protégés. C'est peut-être en utilisant l'outil de Code::Blocks pour créer une nouvelle classe que le mot-clé 'protected' a été utilisé. Mais je pense que maintenant, tant que je ne crée pas une classe qui hérite d'une 2e classe, je mettrais en privé dans la 2e, et demanderais conseils pour quoi mettre en protégé.

    Aussi, la méthode afficheTout, méthode horrible par excellence, qui me révulse à chaque fois que je la vois.
    Ah ! j'en ai déjà parlé plus haut, je la supprime et je modifie la surcharge d'opérateur.

    Aussi, l'implémentation de ostream << Rectangle est ... originale ? (Pourquoi 177 ?)
    Originale ? quelque chose ne vas pas ?
    177, parce qu'en faisant une bête boucle, j'ai affiché en console tout les caractères ASCII, et j'ai choisie le caractère numéro 177. Tu peux regarder à quoi il ressemble si tu veux.

    @ Ekleog : Je ne vois absolument pas ce que sont les NVI, et dans la phrase :
    Enfin, je dirais qu'il y a peut-être une sur-représentation des fonctions virtuelles publiques. Voir peut-être NVI (Non Virtual Interface), qui pourrait être avantageux.
    Qu'est-ce qu'une sur-représentation ?

    @ Hylvenir :
    Il ne manquerait pas des constructeurs par copie, et des opérateur d'affectations ? (pour éviter des bugs sur les compteurs de nombres de forms, ...)
    Je n'avais effectivement pas pensé à la copie pour le nombre de formes. Je les implémente.
    Si on copie un objet dans un autre, c'est que les deux ont déjà été créé. Les modifications du nombre de formes va donc passer par le constructeur et le destructeur avant et après, mais pas pendant la copie, donc le compte est bon, je me trompe ?.
    Et si on a un truc du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void fonctionQuiRecupereUnRectangle(const Rectangle& r); // implémentation autre part
     
    /// ...
     
    fonctionQuiRecupereUnRectangle(Rectangle(1, 2));
    L'objet est créé, récupéré, puis supprimé, ça passe par constructeur et destructeur, donc le compte est bon, je me trompe toujours ?
    J'oublie sûrement des cas...

    @ cob59:
    Dans UtFormes(), les instanciations dynamiques de tes formes (via new/delete) sont inutiles. Un Rectangle r1(2, 3); serait plus simple et plus approprié.
    Je sais qu'il ne sont pas appropriés, mais j'ai oublié de signaler qu'en faisant ça, je souhaitais simplement pouvoir détruire un des objets avant la fin du main, et pouvoir vérifier que le nombre de formes restait correct.
    Mais s'il y a un autre moyen, ne vous gênez pas

    @Kaamui :
    Y a-t'il un intérêt à avoir un header pour le main.cpp ?
    Ici, je pense aussi que pas vraiment. Mais je le fais systématiquement, parce que je préfère avoir un simple '#include "main"', que le tout dans le main.cpp. N'hésitez pas à dire si vous pensez que le mieux est d'en faire un ou pas ici. Moi, je pense que ce n'est qu'une simple question de choix de lisibilité.

    Voilà, merci encore pour votre participation, je fais mes modifications sur Code::Blocks, je les posterai dès 14h30 si j'ai le temps.

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    En fait, il n'est pas fonctionnel
    J'ai les erreurs :
    error: no matching function for call to 'Forme::perimetre() const'
    note: candidates are: virtual float Forme::perimetre() <near match>


    Évidemment, puisque la version non statique est virtuelle pure.
    En fait, perimetreDe(), je l'ai faite en pensant que du coup, on aurait pas besoin de créer un objet de type rectangle pour connaître l'aire/le périmètre d'un rectangle d'une certaine largeur et d'une certaine longueur.
    ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perimetreDe(Rectangle(5, 8));
    Même principe pour l'aire (je suppose que vous vous en doutiez que c'est ce que je voulais faire, mais sait-on jamais...).
    Mais du coup, je ne vois pas comment je pourrais faire. Puissiez-vous m'indiquer la voie...
    Et si je les laisse tout simplement virtuelles non pures, ce n'est plus une classe abstraite, et je ne souhaite pas que l'on puisse instancier un objet de type Forme.

  13. #13
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Citation Envoyé par loukiluk Voir le message
    Je sais qu'il ne sont pas appropriés, mais j'ai oublié de signaler qu'en faisant ça, je souhaitais simplement pouvoir détruire un des objets avant la fin du main, et pouvoir vérifier que le nombre de formes restait correct.
    Mais s'il y a un autre moyen, ne vous gênez pas
    Tu peux créer un scope "anonyme" à la fin duquel tes objets seront détruits.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void UtFormes() {
     
      {
        Rectangle r1(1, 2);
      } // <-- r1 est détruit ici
     
    }

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    Ah, mais oui, je connaissais cette technique en plus, honte à moi

  15. #15
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Salut,

    J'ai lu en diagonale la discussion alors vous m'excuserez si ça a été dit

    Je ne vois pas pourquoi Forme n'est pas une classe abstraite, pour savoir si tu dois ou non faire d'une classe une classe abstraite (avec les =0 que tu as mis en commentaires), demande toi si ça a un sens d'instancier cette classe, ici ça n'a pas de sens.

    D'une manière générale, on ne met pas d'affichage dans ce genre de classe (je pense à std::cerr) mais on lance une exception au lieu de quitter brutalement.

    Pourquoi veux-tu compter les instances ? A quoi ça sert ?

  16. #16
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    Pour l'instant, tu n'as pas répété des choses déjà dites

    Je ne vois pas pourquoi Forme n'est pas une classe abstraite, pour savoir si tu dois ou non faire d'une classe une classe abstraite (avec les =0 que tu as mis en commentaires), demande toi si ça a un sens d'instancier cette classe, ici ça n'a pas de sens.
    Effectivement, après les commentaires de tout le monde et ma cogitation sur les méthodes virtuelles pures, j'ai remarqué que y'avait un truc qui clochait.
    Donc, alors, au revoir la structure 'Forme'.
    Je crois qu'en fait, la classe Forme voulait me permettre de compter le nombre de formes, donc du nombre d'objets instanciés qui ont pour type une classe héritée de Forme.
    Sans la classe Forme, je pourrais déclarer une variable globale dans un .h, que j'incrémenterais dans les classes Rectangle et Carre, qui incluraient ce .h, mais ça me semble du bricolage maladroit...

    D'une manière générale, on ne met pas d'affichage dans ce genre de classe (je pense à std::cerr) mais on lance une exception au lieu de quitter brutalement.
    J'ai lu le début d'un tuto sur les exceptions, avec les histoires de try et de catch...
    Mais je considérais que ma priorité était de m'améliorer, avant de lire des trucs qui m'embrouillent, et d'apprendre trop de choses que je ne maîtrise pas.
    Alors donc, bah, je le fais comme ça, comme en C, en fait. Mauvais réflexe, je sais.
    Mais pour l'instant, je ne connais pas autre chose.

    Pourquoi veux-tu compter les instances ? A quoi ça sert ?
    J'attendais cette question. Effectivement, ça sert à rien ici. Mais je sens que ça pourrait me servir un jour, et que j'aimerais maîtriser ce principe pour ne pas l'utiliser comme un pied en temps voulu. Et là, j'en viens à : comment on fait alors ?
    Hum... bref, j'apprécierais beaucoup que l'on m'explique tout. Mais si c'est expliqué dans un tuto, je le lirais volontiers.

    Merci pour ta participation

  17. #17
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Donc, alors, au revoir la structure 'Forme'.
    Non tu n'es pas obligé de la supprimer, c'est bien d'avoir une "interface" commune à toutes les formes.

    Une autre chose, pourquoi mets-tu un "s" à la fin du nom de tes fichiers ?

    Mais je considérais que ma priorité était de m'améliorer, avant de lire des trucs qui m'embrouillent, et d'apprendre trop de choses que je ne maîtrise pas.
    Ça ne t'embrouillera pas, c'est assez simple à comprendre par rapport à d'autres notions comme le polymorphisme.

    J'attendais cette question. Effectivement, ça sert à rien ici. Mais je sens que ça pourrait me servir un jour, et que j'aimerais maîtriser ce principe pour ne pas l'utiliser comme un pied en temps voulu. Et là, j'en viens à : comment on fait alors ?
    Franchement pas sûr que ça te servira vraiment... Par exemple, savoir si 0 ou 1 instance est créée, ça sert parfois et ça s'appelle le pattern singleton. Maintenant si jamais tu devais compter, je créerais une classe CarreFactory, qui aurait la responsabilité de compter les classes qu'il crée, regarde du côté du pattern factory (bien que ça n'a rien avoir avec le fait de compter, disons qu'on peut juste s'en servir pour ça). Enfin, je pense que quand t'en aura vraiment besoin, t'auras plus d'expérience et tu sauras comment faire...

    Ensuite vu que tu viens du C, je te conseille de lire les 5 premiers items du livre de Scott Meyer : Effective C++, qui sont dédiés à ton cas.

  18. #18
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    Non tu n'es pas obligé de la supprimer, c'est bien d'avoir une "interface" commune à toutes les formes.
    Ben, j'ai cru que c'était ce que tu voulais dire par là :
    demande toi si ça a un sens d'instancier cette classe, ici ça n'a pas de sens
    Du coup, je vais la remettre, et elle devra donc être non abstraite.
    Dites-moi si je me trompe. En attendant, je code.

    Une autre chose, pourquoi mets-tu un "s" à la fin du nom de tes fichiers ?
    Aucune idée >_< mais maintenant qu'ils sont nommés comme ça, je ne pense pas que ça pose de problème.

    Ça ne t'embrouillera pas, c'est assez simple à comprendre par rapport à d'autres notions comme le polymorphisme.
    Ah, d'accord.
    J'ai un pote qui fait de la programmation depuis la 6e, et qui a un très bon niveau (enfin, je pense), et il m'a conseillé de lire le tuto sur la programmation par contrat.
    Et la programmation par contrat, j'ai pas tout compris (et j'ai pas finis de le lire).
    A ton avis, je devrais apprendre les exceptions d'abord ?

    Enfin, je pense que quand t'en auras vraiment besoin, t'auras plus d'expérience et tu sauras comment faire...
    Je vais suivre ton conseil.

    Ensuite vu que tu viens du C, je te conseille de lire les 5 premiers items du livre de Scott Meyer : Effective C++, qui sont dédiés à ton cas.
    Il me semble être allé lire les première phrases, je vais aller le lire en entier.
    En attendant, si vous continuez à commenter mon code jusqu'à ce que vous pensez qu'il pourrait difficilement être mieux, ça serait géniale

    EDIT : J'ai refait le code, sans les exceptions pour l'instant et avec la structure Forme.
    Par contre, je ne vois pas trop l'intérêt de Forme, là...

  19. #19
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Du coup, je vais la remettre, et elle devra donc être non abstraite.
    Dites-moi si je me trompe. En attendant, je code.
    On peut instancier une classe non-abstraite... Ce qui n'a pas de sens ici, il faut qu'elle soit abstraite, donc dans le jargon C++ "virtuelle pure", c'est-à-dire avec les "=0" derrière le nom des fonctions. L'intérêt c'est de pouvoir avoir une collection de forme (dans un vector par exemple) et de pouvoir faire du polymorphisme.

    J'ai un pote qui fait de la programmation depuis la 6e, et qui a un très bon niveau (enfin, je pense), et il m'a conseillé de lire le tuto sur la programmation par contrat.
    Et la programmation par contrat, j'ai pas tout compris (et j'ai pas finis de le lire).
    A ton avis, je devrais apprendre les exceptions d'abord ?
    C'est pas bien compliqué, par exemple, soit une fonction qui attend un entier, et tu voudrais, pour les besoins de la fonction, que cet entier soit entre 1 et 65536 (par exemple c'est un port).
    Concrètement:

    La question que tu dois te poser est : "Que faire si a est < 1 ou > 65536 ?".

    Tu as deux choix :

    • Soit tu fais confiance à l'utilisateur et tu dis que l'entier a sera toujours toujours dans les bornes. Donc en bref, tu ne vérifies pas le paramètre.
    • Soit tu retournes un code d'erreur ou lève une exception si a n'est pas dans les bornes pour dire à l'utilisateur qu'il n'a pas respecté le contrat.


    Dans la programmation par contrat, tu spécifies les pré-conditions, les post-conditions et le résultat (ce que tu retournes). Par exemple:

    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
     
    /*
      pre: 0 < a <= 65536
      post: a est inchangé.
      throw: invalid_port si a est invalide (3).
      résultat: Le descripteur de fichier du serveur avec le port a. Ou -1 si a est invalide (4).
    */
    int ouvrir_serveur(int &a)
    {
      // (1)
      assert(a > 0 && a <= 65536);
      // (2)
      if(a <= 0 || a > 65536)
        throw new invalid_port(); // (3)
        return -1; // (4)
      // (5)
    }
    Le paramètre a est passé par référence (complétement idiot ici, mais c'est pour montrer une post-condition), d'autant plus qu'on pourrait ajouter le mot clé "const" pour assurer que a ne sera pas modifié. (Mais le mieux serait de ne simplement pas mettre de référence, dans ce cas, il n'y aurait pas de post-condition). C'est utile par exemple si tu passes un objet par référence que tu vas modifié sous certaines conditions, et d'une certaine façon.

    (1), on utilise un assert, c'est pas terrible dans ce cas, car ils sont juste activés quand on debug (et encore heureux car ça quitte le programme directement avec un message). C'est très bien pour vérifier les erreurs de codage, mais ici, "a" pourrait être précisé par l'utilisateur en release..

    (2) On vérifie si a est bien dans les bornes et sinon on fait :
    (3) Soit on lance une exception
    (4) Soit on renvoie un code d'erreur (-1) (C'est la façon usuel en C)

    (5) On ne vérifie rien, et on suppose que l'utilisateur à lui-même vérifié "a". Le contrat est juste écrit dans les pré-conditions.

    La notion de contrat peut être "incorporée" au langage, mais en C++ ça ne l'est pas... Donc c'est le programmeur qui use des techniques sus-cités pour établir le contrat.

  20. #20
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 29
    Points : 25
    Points
    25
    Par défaut
    Merci pour la réponse.

    En fait, j'avais compris la notion de contrat, mais ce que je ne comprenais pas, c'est quand il parle avec des mots comme "invariants de classe".
    J'arrive à comprendre à peu près, mais je pense que la relecture, rerelecture, etc... devrait suffire. C'est la 1ere fois que je lis un tutoriel C++ (presque) entièrement théorique.

    Mais tes explications m'ont aidés à comprendre

    Avant de continuer l'exercice 1 de wikipedia, je vais d'abord apprendre à utiliser les exceptions, puis je vais terminer le tuto sur la programmation par contrat, parce que je vois que tu utilises la fonction 'assert', que je ne connais pas.

    Merci encore

Discussions similaires

  1. [Projet en cours] Tetris amateur - vos avis sur mon code ?
    Par NainTernaute dans le forum Projets
    Réponses: 24
    Dernier message: 04/05/2010, 22h44
  2. [FFT] Votre avis sur mon code
    Par deubelte dans le forum C++
    Réponses: 1
    Dernier message: 10/02/2007, 20h14
  3. Vos avis sur mon site
    Par kodokan dans le forum Mon site
    Réponses: 11
    Dernier message: 10/10/2006, 21h06
  4. Réponses: 1
    Dernier message: 06/10/2006, 21h03
  5. Vos avis sur mon site perso
    Par Fildz dans le forum Mon site
    Réponses: 12
    Dernier message: 19/08/2006, 22h07

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