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 :

Relations UML et C++


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par défaut Relations UML et C++
    Bonjour à tous,

    J'ai une question concernant la traduction de relations UML en C++: si on considère que j'ai deux classes A et B avec une relation plusieurs à plusieurs entre ces classes. J'aimerai pouvoir à partir d'un object A lister l'ensemble des objets B qui lui sont liés et à partir d'un objet B lister l'ensemble des objets A qui lui sont liés. Donc ma question : comment gérez vous ce type de relation dans vos codes? personnellement, je suis parti sur un truc du genre:
    définition des classes:
    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
     
    class A;
    class B;
     
    class A
    {
    private:
        set<B*> _lstpB;
    public:
        ~A();
        void addRelB(B* const ptB);
        void removeRelB(B * const ptB);
    };
     
    class B
    {
    private:
        set<A*> _lstpA;
    public:
        ~B();
        void addRelA(A* const ptA);
        void removeRelA(A* const ptA);
    };
    et pour le code:
    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
     
    #include "head.h"
    #include <iostream>
     
    A::~A()
    {
        cout << "destructeur de A" << endl;
        set<B*>::iterator it = _lstpB.begin();
        while (it != _lstpB.end())
        {
            (*it)->removeRelA(this);
            it = _lstpB.begin();
        }
    }
     
    void A::addRelB(B* const ptB)
    {
        cout << "ajout d'une relation A->B" << endl;
        if (ptB != NULL)
        {
            if (_lstpB.insert(ptB).second)
            {
                cout << "demande d'ajout d'une relation B->A" << endl;
                ptB->addRelA(this);
            }
            else
                cout << "la relation A->B existe deja" << endl;
        }
    }
     
    void A::removeRelB(B * const ptB)
    {
        cout << "suppression d'une relation A->B" << endl;
        if (ptB != NULL)
        {
            if (_lstpB.erase(ptB) != 0)
            {
                cout << "demande de suppression d'une relation B->A" << endl;
                ptB->removeRelA(this);
            }
            else
                cout << "la relation A->B est deja supprimee" << endl;
        }
    }
     
     
    B::~B()
    {
        cout << "destructeur de B" << endl;
        set<A*>::iterator it = _lstpA.begin();
        while (it != _lstpA.end())
        {
            (*it)->removeRelB(this);
            it = _lstpA.begin();
        }
    }
     
    void B::addRelA(A* const ptA)
    {
        cout << "ajout d'une relation B->A" << endl;
        if (ptA != NULL)
        {
            if (_lstpA.insert(ptA).second)
            {
                cout << "demande d'ajout d'une relation A->B" << endl;
                ptA->addRelB(this);
            }
            else
                cout << "la relation B->A existe deja" << endl;
        }
    }
     
    void B::removeRelA(A* const ptA)
    {
        cout << "suppression d'une relation B->A" << endl;
        if (ptA != NULL)
        {
            if (_lstpA.erase(ptA) != 0)
            {
                cout << "demande de suppression d'une relation A->B" << endl;
                ptA->removeRelB(this);
            }
            else
                cout << "la relation B->A est deja supprimee" << endl;
        }
    }
    Je me demande si c'est la bonne approche, elle me permet d'être sûr que mes données sont correctement reliées (lorsqu'on ajoute ou retire une relation ou lorsqu'un des objets est détruit) mais je trouve ça un peu "lourd" c'est pour ça que je me demande comment vous gérez les relations notamment les n-n dans vos codes C++

  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 : 50
    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
    Par défaut
    Une solution est d'utiliser les boost::bimap.
    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
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

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

    Je sais que ma proposition peut nécessiter un aménagement de ton diagramme de classes, mais, j'ai pris l'habitude, à cause des bases de données, d'éviter les relation n-n et d'intercaler un mécanisme (pour rester générique ) qui me permette de ne gérer que des relations un à plusieurs.

    L'idée est donc, peut être, de créer une classe que nous nommerons, par exemple ABMediator, qui serait (qui s'en doute ) adapté sur base du DP... médiateur, et à qui les éléments de type A et les éléments de type B se reporteraient pour la gestion des relations.

    Cette classe intermédiaire disposerait de "tous les A" et de "tous les B", chaque A et chaque B auraient une référence unique sur le médiateur, et ce serait ce serait à ce dernier de gérer les relations de multiplicité
    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
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par défaut
    Merci pour ces réponses,
    @JolyLoic, ce n'est pas pour un projet perso et je ne peut pas utiliser boost
    @koala01, c'est une bonne idée que j'utilisai déjà. Ca permet effectivement d'être très proche du modèle de données stocké dans une BD mais ça a l'inconvénient de multiplier les classes
    J'ai pensé à utiliser un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include <set>
    template<typename classe, typename objet, typename conteneur = std::set<objet*> >
    class Relation
    {
    private:
         conteneur _lstpObj;
    public:
         ~Relation();
         void addRel(objet* const obj);
         void removeRel(objet* const obj);
    };
    #include "head.tpp"
    avec
    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
     
    template<typename classe, typename objet, typename conteneur>
    Relation<classe, objet, conteneur>::~Relation()
    {
         conteneur::iterator it = _lstpObj.begin();
         while (it != _lstpObj.end())
         {
              (*it)->removeRel(static_cast<classe*>(this));
              it = _lstpObj.begin();
         }
    }
     
    template<typename classe, typename objet, typename conteneur>
    void Relation<classe, objet, conteneur>::addRel(objet* const obj)
    {
         if (_lstpObj.insert(obj).second)
              obj->addRel(static_cast<classe*>(this));
    }
     
    template<typename classe, typename objet, typename conteneur>
    void Relation<classe, objet, conteneur>::removeRel(objet* const obj)
    {
         if (_lstpObj.erase(obj) != 0)
              obj->removeRel(static_cast<classe*>(this));
    }
    et donc je peux l'utiliser comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class A : public Relation<A, B>
    {};
    class B : public Relation<B, A>
    {};
    Qu'en pensez-vous sachant que je spécialiserai ma classe Relation pour les différents types de conteneur et que je gérerai les erreurs par exception (notamment dans le cas de paramètres NULL)

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Le transtypage dans les différentes méthodes ne me semblent même pas nécessaire...

    En effet, un A va travailler avec un B* et inversément (un B avec un A*).

    Comme A et B héritent d'une spécialisation de Relation, quand tu fais
    obj->remove(this), tu lui passe automatiquement le bon type (du moins, il me semble )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Par défaut
    Ben dans le principe je suis d'accord avec toi, mais si je ne met pas le static_cast, le compilateur me mets:
    error C2664: 'Relation<classe,objet>::removeRel' : impossible de convertir le paramètre 1 de 'Relation<classe,objet> *const ' en 'A *const '
    with
    [
    classe=B,
    objet=A
    ]
    and
    [
    classe=A,
    objet=B
    ]
    Les types pointés n'ont aucun rapport entre eux ; conversion nécessitant reinterpret_cast, cast de style C ou cast de style fonction
    (j'utilise Visual 2003) de plus j'ai un autre problème, si par exemple j'ai les classes A, B et C avec A<-->B<-->C chaque relation est de type n-n mon idée est de faire un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class A : public Relation<A, B> {};
    class B : public Relation<B, A>, public Relation<B, C> {};
    class C: public Relation<C, B> {};
    Mais là le compilateur râle encore:
    error C2385: accès ambigu de 'removeRel' dans 'B'
    est peut-être le 'removeRel' en base 'Relation<B,A>::removeRel'
    ou le 'removeRel' en base 'Relation<B,C>::removeRel'
    c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xtree(267)*: lors de la compilation de la fonction membre du modèle de classe 'Relation<classe,objet>::~Relation(void)'
    with
    [
    classe=A,
    objet=B
    ]
    Il faut donc que je mette le nom complet: par exemple pour la méthode removeRel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<typename classe, typename objet>//, typename conteneur>
    void Relation<classe, objet>::removeRel(objet* const obj)
    {
         if (_lstpObj.erase(obj) != 0)
              obj->Relation<objet, classe>::removeRel(static_cast<classe*>(this));
    }
    Ce qui jusque là n'est pas très pratique mais passe encore, le dernier problème que j'ai c'est que lorsque pour un élement de la classe B, j'appelle addRel, le compilateur ne sais pas différencier entre la méthode provenant du premier héritage (Relation<B,A>) de celle provenant du second (Relation<B,C>). Hors le prototype de addRel est dans un cas: void addRel(A* const) et dans l'autre: void addRel(C* const). Donc le compilateur devrait pouvoir les différencier (en tout cas ça me semble logique). Je testerai ce soir avec VS2005.

Discussions similaires

  1. Aide relation UML
    Par skouza dans le forum Diagrammes de Classes
    Réponses: 2
    Dernier message: 10/05/2011, 09h32
  2. [TOP CASED] nommer une relation UML
    Par math32 dans le forum Autres
    Réponses: 1
    Dernier message: 24/06/2010, 21h12
  3. UML : quelle relation avec les SGBD ?
    Par startin dans le forum UML
    Réponses: 8
    Dernier message: 10/04/2007, 10h54
  4. Passer de UML au modèle entité-relation ?
    Par condor_01 dans le forum Diagrammes de Classes
    Réponses: 2
    Dernier message: 19/02/2007, 13h55
  5. relation uml+ BD
    Par tinhinan6 dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 06/02/2007, 15h45

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