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 :

Reorganisation modulaire et problème


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut Reorganisation modulaire et problème
    Bonsoir,

    J'avais toutes les classes de mon programme dans un seul header,j'ai donc décidé de le rendre modulaire

    Mais il y a un soucis dont je ne vois pas la cause ..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Undefined symbols for architecture x86_64:
      "Vehicule::createVehicule(std::string)", referenced from:
          _main in main-aV2PNG.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    make: *** [main] Error 1
    main.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <iostream>
    #include "Vehicule.h"
     
     
    int main()
    {
        Vehicule *v=Vehicule::createVehicule("fr");
        presenter(v);
        return 0;
    }
    Vehicule.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
    #include <iostream>
     
    class Vehicule
    {
    public:
        virtual std::string getMarque() const =0;
        friend std::ostream &operator<<(std::ostream &o,const Vehicule *v);
        static Vehicule* createVehicule(std::string origine);
    };
     
    void presenter(const Vehicule *v)
    {
        std::cout << "Vehicule " << v << std::endl;
    }
     
    std::ostream &operator<<(std::ostream &o,const Vehicule *v)
    {
        return o << v->getMarque();
    }
    Vehicule.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "Vehicule.h"
    #include "CreateurConcretRenault.h"
    #include "CreateurConcretFiat.h"
     
    Vehicule* Vehicule::createVehicule(std::string origine)
    {
        if(origine=="fr") return new CreateurConcretRenault();
        else if(origine=="ita") return new CreateurConcretFiat();
     
        else return new CreateurConcretRenault();
    }
    CreateurConcretRenault.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #include <iostream>
    #include "Vehicule.h"
     
    class CreateurConcretRenault : public Vehicule
    {
    public:
        std::string getMarque() const;
    };
    CreateurConcretRenault.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include "CreateurConcretRenault.h"
     
    std::string CreateurConcretRenault::getMarque() const
    {
        return "Renault";
    }
    CreateurConcretFiat.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <iostream>
    #include "Vehicule.h"
     
    class CreateurConcretFiat : public Vehicule
    {
    public:
        std::string getMarque() const;
    };
    CreateurConcretFiat.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include "CreateurConcretFiat.h"
     
    std::string CreateurConcretFiat::getMarque() const
    {
        return "Fiat";
    }
    Dernière modification par Invité ; 27/07/2013 à 20h41.

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Tu utilises quelle ligne de commande pour linker ton code ?
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

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

    Informations professionnelles :
    Activité : aucun

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

    Les erreurs de type "undefined reference to" sont des erreurs spécifiques de l'éditeur de liens (link avec Vc++, ld avec gcc). Il t'indique qu'il ne trouve pas le code binaire de la fonction en question.

    La raison la plus fréquente (si on excepte celle qui est d'avoir oublié d'implémenter une fonction ) est, tout simplement, que tu n'as pas indiqué le fichier objet (*.obj ou *.o, en fonction du compilateur) dans la liste des fichiers à utiliser pour cette étape.

    Ceci dit, ton code est une véritable horreur du point de vue de la conception, et je voudrais attirer ton attention sur les erreurs les plus flagrantes.

    Saches, pour commencer, que l'héritage est la relation la plus forte qui puisse exister entre deux classes et qu'elle représente littéralement une relation "EST-un". Un objet du type dérivé (ici "CreateurConcretRenault" et "CreateurConcretFiat") sensé être un objet du type de base (ici, véhicule), au sens littéral du terme.

    Comme on ne peut décemment pas estimer qu'un créateur de voiture EST un véhicule (ni même une voiture), l'héritage est sans objet: si tu veux faire hériter "quelque chose" de véhicule, fait plutôt hériter des classes comme "avion", "bateau", "camion", "voiture", "char à voile" ou "patin à roulettes" meme si tu veux, mais, certainement pas une lasse "créateur de véhicules"

    Selon le sens que tu donnes à "CreateurConcretRenault", tu as deux sortes de relations possibles:

    Soit, tu considère que c'est la marque de certains véhicules et tu as donc une relation dans laquelle chaque véhicule dispose de cette information, soit tu mets l'accent sur le fait que CreateurConcretRenault construit différents types de véhicules et tu pourrait, à ce moment là, considérer qu'il... construit (au sens C++ du terme ) des véhicules dont la marque spécifique et Renault (ou Fiat, ou Volkwagen ou ce que tu veux )

    C'est d'autant plus vrai que la variation que ta classe CreateurConcretRenault apporte par rapport à ta classe véhicule consiste en la possibilité d'indiquer quelle est sa marque.

    Or, même si l'on considère que la marque peut apporter d'avantage de précision que le simple fait de dire que c'est "renault" ou "fiat", c'est typiquement le genre de donnée qui fait partie intégrante de n'importe quel véhicule, du camion au patins à roulettes en passant par tout ce qui vole, roule ou navigue

    De plus, il n'est pas de très bon ton de donner à une classe la responsabilité de créer des objets de son propre type, surtout si la classe en question est sensée créer des objets du type dérivé à son type.

    La responsabilité de la création "effective" d'un objet concret peut échoir à beaucoup de choses de manière générale, mais pas à l'objet lui-même.

    C'est un peu comme si tu demandais à un steak de cuisiner lui-même tout le menu dans lequel il apparait, sans oublier le sel, le poivre, la salade, les frites et la sauce qui va avec

    Si tu suis ce raisonnement et que tu le pousses à l'absurde, tu vas finir par demander au véhicule de se détruire lui-même!!!

    Tout ce qui concerne, pour faire simple, la durée de vie des différents objets que tu crées, que ce soit le fait de les construire ou de les détruire, doit être "délégué" à "quelque chose" dont c'est la (seule) responsabilité.

    Bien sur, le destructeur de ta classe veillera à faire "correctement" le ménage lorsque l'objet est détruit, tout comme le constructeur veillera à initialiser correctement chaque membre de l'objet lorsqu'il est construit, mais ce n'est en aucun cas à l'objet lui-meme de lancer le processus

    Si tu veux déléguer la création de tes véhicules de manière à ce que l'utilisateur puisse se contenter de gérer le véhicule créé comme un véhicule, sans avoir à s'inquiéter du type réel, il vaut mieux utiliser le patron de conception "fabrique" (factory en anglais) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #ifndef FABRIQUE_H
    #define FABRIQUE_H
    class Vehicule;
    class Fabrique{
        public:
            Vehicule * creeVehicule(std::string const & pays);
    };
    #endif // FABRIQUE_H
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <Fabrique.h>
    #include <Fiat.h>
    #include <Renault.h>
     
    Vehicule * Fabrique::creeVehicule(std::string const & pays){
        if(pays =="Fr")
            return new Renault;
        return new Fiat;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <Fabrique.h>
    #include <Vehicule.h>
    int main(){
       Fabrique f;
       Vehicule * v1 = f.creeVehicule("Fr");
       Vehicule * v2 = creeVehicule("It");
       std::cout<<v1->getMarque()<<std::endl
                <<v2->getMarque()<<std::endl;
        delete v1;
        delete v2;
        return 0;
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Invité
    Invité(e)
    Par défaut
    En effet,

    J'essayais d'implémenter le pattern Abstract Factory que je ne comprenais pas très bien.
    Décidément, ce n'est pas en quelques jours que ça passera ! Ca me rassure

    Merci des infos !

    Edit :
    Du coup , ça te dérangerait , quand tu auras le temps , de me donner ton avis sur une implémentation du pattern Builder ? Me remettre en place quoi !


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    class Voiture /* L'objet complexe */
    {
     
    private:
        std::string portiere;
        std::string siege;
     
    public:
        void setPortiere(std::string p);
        void setSiege(std::string s);
        friend std::ostream &operator<<(std::ostream &o,const Voiture *v);
    };
     
     
    void Voiture::setPortiere(std::string p) {  portiere=p; }
     
    void Voiture::setSiege(std::string s)  { siege=s; }
     
    std::ostream &operator<<(std::ostream &o,const Voiture *v)
    {
        return o << "Portière en " << v->portiere << " et signe en " << v->siege;
    }
     
    class MonteurVoiture /* Le monteur/builder : définit l'interface des méthodes utiles à l'assemblage de l'objet */
    {
     
    protected:
        Voiture *v;
     
    public:
        void createVoiture();
        Voiture *getVoiture();
        virtual void addPortiere() =0;
        virtual void addSiege() =0;
        static MonteurVoiture* instanceVoiture(std::string type);
     
    };
     
    void MonteurVoiture::createVoiture()
    {
        v=new Voiture();
    }
     
    Voiture* MonteurVoiture::getVoiture() { return v; }
     
     
    class MonteurVoitureLuxe : public MonteurVoiture /* ConcreteBuilder  : va assembler les différents composants de l'objet */
    {
     
    public:
        void addPortiere();
        void addSiege();
     
    };
     
    void MonteurVoitureLuxe::addPortiere() { v->setPortiere("Acier blindé"); }
    void MonteurVoitureLuxe::addSiege() { v->setSiege("Cuir"); }
     
    class MonteurVoitureOrdinaire : public MonteurVoiture /* ConcreteBuilder  : va assembler les différents composants de l'objet */
     
    {
     
    public:
        void addPortiere();
        void addSiege();
     
    };
     
    void MonteurVoitureOrdinaire::addPortiere() { v->setPortiere("Tôle"); }
    void MonteurVoitureOrdinaire::addSiege() { v->setSiege("Tissu"); }
     
     
    class Atelier /* Director qui va executer les méthodes du monteur */
    {
     
    private:
        MonteurVoiture *monteur;
     
    public:
        Atelier(MonteurVoiture *m) { monteur=m; }
        Voiture *doTheJob();
    };
     
    Voiture* Atelier::doTheJob()
    {
        monteur->createVoiture();
        monteur->addPortiere();
        monteur->addSiege();
        return monteur->getVoiture();
    }
     
        MonteurVoiture* MonteurVoiture::instanceVoiture(std::string type)
        {
            if(type=="luxe") return new MonteurVoitureLuxe();
            else return new MonteurVoitureOrdinaire();
        }
    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
    #include <iostream>
    using namespace std;
    #include "Voiture.h"
     
    int main()
    {
     
        MonteurVoiture *m=MonteurVoiture::instanceVoiture("luxe");
        Atelier a(m);
        cout << a.doTheJob() << endl;
        return 0;
     
    }
    Je n'ai pas touché le code après avoir lu tes remarques.
    Mais niveau implémentation , je pense que c'est déjà mieux que le précédent pattern niveau héritage et classe qui s'occupe d'exécuter les méthodes. Bon signe ?
    Dernière modification par Invité ; 29/07/2013 à 08h40.

Discussions similaires

  1. [ZF 1.11] appli modulaire et problème d'accès actions
    Par BBFUNK01 dans le forum MVC
    Réponses: 6
    Dernier message: 01/04/2012, 21h03
  2. Réponses: 4
    Dernier message: 03/02/2010, 12h49
  3. Problème debugger en programmation modulaire
    Par Henri dans le forum Code::Blocks
    Réponses: 0
    Dernier message: 04/12/2007, 11h56
  4. Problème d'exponentiation modulaire
    Par Superne0 dans le forum Mathématiques
    Réponses: 16
    Dernier message: 11/11/2007, 15h52
  5. Problème de refresh dans une application modulaire
    Par TigrouMeow dans le forum Windows Forms
    Réponses: 8
    Dernier message: 11/10/2007, 15h06

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