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 :

C++ , relations entre classes


Sujet :

C++

  1. #21
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 60
    Points : 50
    Points
    50
    Par défaut
    Et il est preferable d'utiliser assez rapidement les auto_ptr et les shared_ptr qui permettent d'allegerla gestion de l'allocation dynamique de memoire
    Cours et ateliers d'initiation à la mosaique LesPierresArcEnCiel

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

    Informations professionnelles :
    Activité : aucun

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

    On pourrait répondre à toutes tes questions de la manière suivante:
    De manière générale, il faut préférer la gestion "statique" (AKA sur la pile) de la mémoire d'un objet plutôt que sa gestion "dynamique" (AKA sur le tas).

    Cela sous entend que, tant que tu peux faire autrement, tu ne devrais pas avoir recours aux pointeurs.

    Le corollaire de cela est que tu devrais utiliser éventuellement les conteneurs de la STL si tu envisage de "regrouper" plusieurs membres d'un même type.

    Les méthodes renvoyant un membre renvoyant alors une référence sur le membre en question (constante, ou non, en fonction des besoins)

    Les exception à ces règles sont relativement simples:
    1. Si un membre d'une de tes classes doit survivre à la destruction de l'objet qui le contient
    2. Si le membre représente en réalité le "conteneur" alors que la classe représente le "contenu" (exemple: un membre Usine dans une classe Travailleur)
    3. Si le membre est du même type (ou d'une classe de base/dérivée) que la classe (exemple: un membre de type Noeud dans la classe... Noeud)
    4. Si tu dois pouvoir profiter du polymorphisme, avec les méthodes virtuelles et autres astuces
    5. Si un membre peut ne pas exister (à ne pas confondre avec "peut ne pas être initialisé), et que tu veux pouvoir en tester l'existence

    alors, tu devra faire appel aux pointeurs, et vraisemblablement à l'allocation dynamique.

    Les méthodes renvoyant ces membres renvoyant alors un pointeur vers ces membres (constant ou non selon les besoins)

    A noter que, pour le premier cas, il peut s'avérer utile d'avoir une classe séparée dont la responsabilité sera, justement, de gérer les éléments alloués dynamiquement, et que dans le deuxième cas, le pointeur peut pointer vers un élément créé de manière "statique".
    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

  3. #23
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Citation Envoyé par koala01 Voir le message
    De manière générale, il faut préférer la gestion "statique" (AKA sur le tas) de la mémoire d'un objet plutôt que sa gestion "dynamique" (AKA sur la pile).
    Bizarre je croyais que c'était l'inverse :
    FAQ C Qu'est ce que sont la pile et le tas ?
    Citation Envoyé par FAQ C
    La pile et le tas sont 2 parties dans lesquelles sont stockées les variables.
    La pile, de taille plus réduite, contient les variables automatiques, les variables locales des fonctions, .... Elles sont détruites automatiquement.
    Par opposition, le tas est d'une taille plus importante et contient les variables allouées dynamiquement. Elles doivent être détruites explicitement.
    Linux > *

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 616
    Points : 30 635
    Points
    30 635
    Par défaut
    Citation Envoyé par befalimpertinent Voir le message
    Bizarre je croyais que c'était l'inverse :
    FAQ C Qu'est ce que sont la pile et le tas ?
    Je me goure à chaque fois... je corrige
    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

  5. #25
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Points : 833
    Points
    833
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je me goure à chaque fois... je corrige
    T'inquiètes pas t'es pas le seul

    Pour répondre au choix sur pointeurs ou références que ce soit pour le passage des paramètres ou les attributs d'une classe, j'aime bien la règle de la FAQ Quand utiliser des références et quand utiliser des pointeurs
    Utilisez les références aussi souvent que possible, et les pointeurs quand vous le devez.
    Vous me direz encore faut il savoir les différences qui existent entre un pointeur et une référence. Mais bon c'est quand même les fondamentaux en C++.
    Linux > *

  6. #26
    Provisoirement toléré
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Points : 495
    Points
    495
    Par défaut shared_ptr, allocations dynamiques et pédagogie
    Disclaimer: Ami débutant en C++, tous les exemples de code de ce message sont faux, archi-faux. Ne viens pas me dire que tu n'étais pas prévenu.

    Citation Envoyé par bdeuu Voir le message
    Et il est préférable d'utiliser assez rapidement les auto_ptr et les shared_ptr qui permettent d'alléger la gestion de l'allocation dynamique de mémoire
    Oui, mais pas trop vite : j'ai observé (ici) que certains commencent à utiliser shared_ptr avant d'avoir compris ce qu'est l'allocation dynamique, d'où des horreurs du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    shared_ptr<A> p;
    A a;
    p.reset (&a);
    Le problème, AMA, est que shared_ptr est présenté comme la baguette magique qui fait qu'on n'a plus à s'embêter à comprendre l'allocation dynamique, et comme un GC intégré au langage (comme si avec les smart pointers C++ devenait Java); alors qu'au contraire, je ne vois pas comment on peut comprendre shared_ptr sans comprendre l'usage correct de delete.

    Le discours : "laisser les shared_ptr gérer les désallocations tous seuls" peut, mal interprété, devenir "je n'ai plus à besoin de comprendre comment ça marche", et conduire à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    shared_ptr<A> p, q;
    p = blah blah;
    q.reset (q.get ());
    Comme quoi, l'absence de conversion implicite (A* -> shared_ptr<A> et shared_ptr<A> -> A*) n'effraie pas certains : ils invoquent plusieurs fonctions membres nommée, pour "convertir" shared_ptr<A> en A* en shared_ptr<A>. (Si ils voulaient "convertir" un A en B, et que la seule fonction qui renvoie un B et prennent A s'appelle A::I_want_to_get_a_B_and_then_die_an_horrible_death(), ils feraient b = a.I_want_to_get_a_B_and_then_die_an_horrible_death(). )

  7. #27
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Pugebad Voir le message
    Ok !!! Merci pour cette explication du passage par référence en C++ , qui nest pas evidente du tout , nous connaissions juste le passage par adresse ou par référence mais en C , ce qui est différent.

    Voila , jai un autre petit souci , ...

    Comment savoir , comment on doit instancier ou tel ou tel objet ? ( par un new , donc un delete pour la destruction , ou creation et destruction auto )

    c'est une question , a laquelle je narrive pas a metre de reponse

    Merchiii
    Ca dépend de la durée de vie de l'instance créée. Si la durée de vie est celle du bloc en cours, la création d'une instance sur la pile suffira:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void f()
    {
      // je n'ai besoin de l'instance de B que pendant l'exécution de f():
      B b;
      // ...
    }
    Si l'instance doit exécuter après que le bloc dans lequel est créée se termine, tu n'as pas le choix: il faut un pointeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    B* f()
    {
      // f() doit créer un objet B, et cet objet est utilisé par le programme
      // après que f() ait été exécuté : 
      B* b = new B;
      // ...
      return b;
    }
    Bien évidemment, la vie n'est pas aussi simple. Dans certains cas, ce n'est pas l'instance qui est importante mais les valeurs qu'elles contient. Quoi qu'il en soit, la façon dont on créée une instance dépends de sa durée de vie.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  8. #28
    Provisoirement toléré
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Points : 495
    Points
    495
    Par défaut
    Citation Envoyé par koala01 Voir le message
    De manière générale, il faut préférer la gestion "statique" (AKA sur la pile) de la mémoire d'un objet plutôt que sa gestion "dynamique" (AKA sur le tas).
    Si j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Simple {
        int i;
        std::string s;
    };
    Simple::i est au une gestion "statique" (AKA sur la pile) ou "dynamique" (AKA sur le tas)? Et pour Simple::s?

    Citation Envoyé par koala01 Voir le message
    Les méthodes renvoyant un membre renvoyant alors une référece sur le membre en question (constante, ou non, en fonction des besoins)
    En général, ça n'est pas une très bonne idée de renvoyer des références sur les membres d'une classe : ça brise l'encapsulation...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 616
    Points : 30 635
    Points
    30 635
    Par défaut
    Citation Envoyé par corrector Voir le message
    Si j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Simple {
        int i;
        std::string s;
    };
    Simple::i est au une gestion "statique" (AKA sur la pile) ou "dynamique" (AKA sur le tas)? Et pour Simple::s?
    c'est une gestion statique (la gestion dynamique, c'est tout ce qui se joue avec des new, new[], delete, delete[]
    En général, ça n'est pas une très bonne idée de renvoyer des références sur les membres d'une classe : ça brise l'encapsulation...
    Qui a bien pu aller te raconter cela

    Si, dans l'ensemble, tu a raison, il semble que tu oublie un concept très important: la const-correctness.

    Tu ne peux pas forcément te passer de renvoyer un membre en tant que référence, pour la principale raison que si tu le passe en tant qu'objet, tu te payera la copie de ce membre - ce qui promet des joyeusetés sans fin s'il s'agit d'autre chose que des types primitifs, et surtout si ce sont des conteneurs de strctutres (ou pire: des conteneurs de pointeurs sur structure)...

    Mais, si tu ne veux pas qu'un membre renvoyé en tant que référence soit modifié, tu n'as qu'à le renvoyer comme référence constante.

    De cette manière, il existera un "contrat" entre toi et le compilateur selon lequel tu t'engage à ne pas aller modifier l'élément, et le compilateur grognera (il s'arrêtera sur une erreur d'ailleurs) si tu essaye de le faire

    [EDIT] la particularité réside dans le fait de renvoyer une référence sur un type primitif.

    Si tu ne les déclares pas comme référence, ils ne seront pas renvoyés en tant que telle (qu'elle soit constante ou non), ce qui fait que le membre ne sera pas modifié si on y chipote par la suite. (le code qui suit te le montrera )

    Par contre, le compilateur refusera d'assigner la référence constante renvoyée par une méthode à une référence non constante, et t'interdira de modifier la référence constante comme l'indiquent les commentaires
    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
    #include <iostream>
    using namespace std;
    struct S
    {
        int i;
        S(int i=1):i(i){}
        const int& geti(){return i;}
    };
    int main()
    {
        S s(10);
        int i=s.geti();
        ++i;
        cout<<"i ="<<i<<endl;
        cout<<"s.i ="<<s.geti()<<endl; //s.i n'a pas été modifié
        //int &j=s.geti();  //NOK référence non constante
        const int& j=s.geti(); //OK j est une référence constante
        //j=15; //NOK: assignation la référence read-only 'j'
        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

  10. #30
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par corrector Voir le message
    En général, ça n'est pas une très bonne idée de renvoyer des références sur les membres d'une classe : ça brise l'encapsulation...

    Peut tu expliquer ton point de vue??

  11. #31
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Je le fais tout le temps pour les matrices ou pour éviter des copies, donc ça dépend des cas.

  12. #32
    Provisoirement toléré
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Points : 495
    Points
    495
    Par défaut
    Citation Envoyé par corrector Voir le message
    En général, ça n'est pas une très bonne idée de renvoyer des références sur les membres d'une classe : ça brise l'encapsulation...
    Citation Envoyé par Mongaulois Voir le message

    Peut tu expliquer ton point de vue??
    Mon point de vue? Ce n'est pas un point de vue, c'est un fait.

    Si tu renvoies une référence sur un membre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class C {
    public:
        T& expose_impl();
     
    private:
        T m;
    };
    alors tu révèles à tous les clients l'existence d'un membre de type T.

    Tu caches son nom, la façon précise de l'allouer. Mais tu exposes son type. Si au départ T est un double, tu ne pourra pas le remplacer par float (disons, pour gagner de la place) sans changer la déclaration de expose_impl, donc l'interface publique de C.

  13. #33
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Cette discussion a déjà eu lieu maintes fois sur le forum, ça serait sympa de ne pas recommencer. De plus, on a répondu à la question initiale, il me semble, donc on peut dire que cette même question est résolue.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Relation entre classes
    Par IsraGab dans le forum C#
    Réponses: 2
    Dernier message: 31/05/2010, 16h12
  2. Réponses: 5
    Dernier message: 19/07/2009, 19h20
  3. Relations entre classes
    Par karim_sousse dans le forum Diagrammes de Classes
    Réponses: 2
    Dernier message: 29/06/2009, 13h24
  4. Relation Entre Class
    Par makaveli_12 dans le forum UML
    Réponses: 2
    Dernier message: 04/02/2009, 12h32
  5. Relation entre classe
    Par guimo26 dans le forum VB.NET
    Réponses: 5
    Dernier message: 25/11/2008, 15h08

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