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

Langage C++ Discussion :

Struct propre à une classe


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Par défaut Struct propre à une classe
    Bonjour.

    Soit une classe MaClasse qui doit gérer une std::map d'éléments constitués par un double + une std::string + un booléen. La question simple que je me pose est : quelle est la méthode la plus "propre" et "classique" de faire ça :
    - créer une classe juste pour un élément
    - créer un structure élément comprenant mon double + std::string + booléen
    - y'a-t-il moyen de rendre la déclaration de cette structure "interne" à la classe (en ce sens qu'il n'y a que cette classe qui a besoin de cette structure) et dans ce cas là quelle est la syntaxe à utiliser ? (déclaration dans le header je suppose mais comment ? (je pense qu'un exemple serait le mieux pour que je comprenne))

    Merci

  2. #2
    Membre chevronné
    Femme Profil pro
    Développeur Java
    Inscrit en
    Décembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Sexe : Femme

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : Finance

    Informations forums :
    Inscription : Décembre 2009
    Messages : 236
    Par défaut
    Bonjour,
    Je pense que d'un point de vue objet le plus propre est de créer une classe, même si je doute que ce soit le plus performant. Apres si tu souhaite que celle ci reste propre à la classe qui l'utilise rien ne t'empeche de créer ta classe en interne.

  3. #3
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    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
    Par défaut
    Citation Envoyé par Kaluza Voir le message
    Bonjour.

    Soit une classe MaClasse qui doit gérer une std::map d'éléments constitués par un double + une std::string + un booléen. La question simple que je me pose est : quelle est la méthode la plus "propre" et "classique" de faire ça :
    - créer une classe juste pour un élément
    - créer un structure élément comprenant mon double + std::string + booléen
    - y'a-t-il moyen de rendre la déclaration de cette structure "interne" à la classe (en ce sens qu'il n'y a que cette classe qui a besoin de cette structure) et dans ce cas là quelle est la syntaxe à utiliser ? (déclaration dans le header je suppose mais comment ? (je pense qu'un exemple serait le mieux pour que je comprenne))

    Merci
    Le mieux est le premier choix : créer une classe, qui se vera dotée de ses propres comportements. La déclaration de class pouvant être imbriquée, on aurait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class A
    {
    public: // pour rendre le type public
      class B
      {
      };
    private:
      std::mon_conteneur<B> m_var;
    };
    [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.

  4. #4
    Membre éclairé
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Par défaut
    Merci beaucoup.

    Par contre, j'aimerai comprendre pourquoi il vaut mieux utiliser une classe qu'un structure ? (si vous avez bien suivi, c'est juste pour stocker un double, une std::string et un booléen)

  5. #5
    Membre très actif
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Par défaut
    En C++ il n'y a aucune différence entre une classe et une structure à part le fait que dans le premier cas les membres sont privés par défaut et dans le second cas les membres sont publics par défaut.
    Mis à part le cas où il ne s'agit que de stocker des données toutes publiques (où l'on utilise plus volontiers le terme structure) dans les autres cas l'usage courant est de recourir à une classe, mais ça ne change absolument rien par ailleurs.
    Voir par exemple :
    http://publib.boulder.ibm.com/infoce...%2Fcplr054.htm

  6. #6
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    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
    Par défaut
    Citation Envoyé par Kaluza Voir le message
    Merci beaucoup.

    Par contre, j'aimerai comprendre pourquoi il vaut mieux utiliser une classe qu'un structure ? (si vous avez bien suivi, c'est juste pour stocker un double, une std::string et un booléen)
    3 données qui ne sont liées par aucune relation n'ont pas à être stockées ensembles. Si les données sont stockées ensemble, j'en déduis qu'il y a de grandes chances qu'il existe une relation entre ces trois données - relation qui dicte le domaine de validité de chacune des données en fonction des autres, probablement.

    Une telle relation est nommée "invariant" dans le jargon abscons des informaticiens. Si L'une des données est publique, alors une partie de l'invariant est exposé, et peut potentiellement être modifié de manière à ce que l'état du trio de variable ne soit plus cohérent (on dit que l'invariant est violé).

    Le fait d'utiliser une classe (avec des méthodes) plutôt qu'une structure (généralement sans méthode, même si en C++, la différence entre classe et structure ne se situe pas du tout à ce niveau ; cf post de ptyxs), c'est qu'on va probablement mettre les données privées et fournir des comportements qui peuvent agir sur l'invariant tout en vérifiant qu'il est toujours valide, quel que soit l'instant où il est examiné par les autres objets.

    Violà pourquoi, dans ton cas, je préconise une classe plutôt qu'une structure.
    [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.

  7. #7
    Membre éclairé
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Par défaut
    Merci pour ce paragraphe qui clarifie les choses.
    Effectivement si le domaine de validité d'un des éléments dépend de l'autre, il faudrait utiliser des éléments privés d'une classe.
    En ce qui me concerne, ce n'est pas le cas (il s'agit de 3 champs indépendants qui renseignent sur la nature de quelque chose, champs que j'ai besoin de stocker dans un conteneur std).

    Je pense donc que dans l'état je peux utiliser une structure (si il y a interdépendance des domaines de validité des éléments, j'utiliserai évidemment une classe)

    Merci encore

  8. #8
    Membre très actif
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Par défaut
    Enfin bon, comme dit plus haut et explicité dans mon lien, j'insiste : en C++ structure et classe c'est blanc bonnet et bonnet blanc (une structure de C++ ce n'est donc pas une structure au sens du C ! une structure du C++ peut avoir des membres privés, tout comme une classe).

  9. #9
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Bonjour,
    Je vais m'éloigner un peu du sujet, mais j'aimerais avoir quelques précisions.

    Citation Envoyé par Emmanuel Deloget Voir le message
    3 données qui ne sont liées par aucune relation n'ont pas à être stockées ensembles. Si les données sont stockées ensemble, j'en déduis qu'il y a de grandes chances qu'il existe une relation entre ces trois données - relation qui dicte le domaine de validité de chacune des données en fonction des autres, probablement.

    Une telle relation est nommée "invariant" dans le jargon abscons des informaticiens. Si L'une des données est publique, alors une partie de l'invariant est exposé, et peut potentiellement être modifié de manière à ce que l'état du trio de variable ne soit plus cohérent (on dit que l'invariant est violé).

    Le fait d'utiliser une classe (...) plutôt qu'une structure (...), c'est qu'on va probablement mettre les données privées et fournir des comportements qui peuvent agir sur l'invariant tout en vérifiant qu'il est toujours valide, quel que soit l'instant où il est examiné par les autres objets.

    Violà pourquoi, dans ton cas, je préconise une classe plutôt qu'une structure.
    Et pour std::pair<T, U> ?
    Les deux données sont publiques, et peuvent être modifiées indépendamment l'une de l'autre, et par n'importe qui.
    Dans ce cas, c'est donc à l'utilisateur qu'il incombe de vérifier que l'invariant est valide, c'est bien ça ?
    Dans le cas où quelle que soit la combinaison des données, l'invariant reste valide, est-ce important/nécessaire de ne pas l'exposer ?

    Un petit exemple concret.
    On dispose d'une classe atome.
    Un littéral est soit un atome (littéral positif), soit la négation d'un atome (littéral négatif).
    Plutôt que de réécrire une classe, j'utilise un std::pair<atome, bool> (en simplifiant).
    Ainsi, si un littéral l est positif (resp. régatif), alors l.second == true (resp. l.second == false).

    Si l'on change la valeur de l'atome sans changer le signe, et inversement, le littéral reste valide et cohérent ; on a simplement changé la valeur du littéral.

    Dans ce cas précis, aurais-tu tout de même utilisé une classe et masqué les données ?

  10. #10
    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,
    Citation Envoyé par Steph_ng8 Voir le message
    Bonjour,
    Je vais m'éloigner un peu du sujet, mais j'aimerais avoir quelques précisions.


    Et pour std::pair<T, U> ?
    Les deux données sont publiques, et peuvent être modifiées indépendamment l'une de l'autre, et par n'importe qui.
    A priori, non, vu que tu veux que seule la classe qui dispose des informations sache qu'il y a une structure sous-jascente

    En outre, on peut présumer que {1.24,"tutu",true} représente une entieté particulière qui est différente de l'entité {1.24,"tutu",false} ou de l'entité {1.24,"tata",true} !

    Les trois représentent peut etre une entité "valide" et qui se trouve dans un "état cohérent", mais, si tu en viens à envisager de maintenir une collection d'éléments composés de trois valeurs, c'est sans doute qu'il y a une relation entre ces trois valeurs!!!

    Autrement, tu gérerait une collection de double d'un coté, une collection de chaies de caractères au milieu et une collection de booléen de l'autre coté
    Dans ce cas, c'est donc à l'utilisateur qu'il incombe de vérifier que l'invariant est valide, c'est bien ça ?
    A partir du moment où plusieurs données sont liées, ce n'est jamais à l'utilisateur de vérifier si les invariants restent valides, parce que, s'il ne le fait pas (et tu peux t'attendre à ce qu'il ne le fasse pas, par oubli ou par paresse ) tu risque de te retrouver avec des objet inconsistants, dans un état aberrant, et de ne pas t'en rendre compte...

    Et ca, c'est le pire qui puisse arriver, car le plus diffile à tracer pour réoudre le problème
    Dans le cas où quelle que soit la combinaison des données, l'invariant reste valide, est-ce important/nécessaire de ne pas l'exposer ?
    c'est moins grave de l'exposer si l'on reste dans l'idée que c'est un invariant "à usage interne exclusif" d'une classe particulière (que tu crées une structre imbriquée).

    Mais ce n'est malgré tout pas une bonne idée pour autant
    Un petit exemple concret.
    On dispose d'une classe atome.
    Un littéral est soit un atome (littéral positif), soit la négation d'un atome (littéral négatif).
    Plutôt que de réécrire une classe, j'utilise un std::pair<atome, bool> (en simplifiant).
    Ainsi, si un littéral l est positif (resp. régatif), alors l.second == true (resp. l.second == false).

    Si l'on change la valeur de l'atome sans changer le signe, et inversement, le littéral reste valide et cohérent ; on a simplement changé la valeur du littéral.

    Dans ce cas précis, aurais-tu tout de même utilisé une classe et masqué les données ?
    Presonnellement, oui...

    Pour plusieurs raisons dont la principale étant qu'il sera beaucoup plus facile de se rendre compte que l'on parle bel et bien d'un litéral et non de n'importe quoi d'autre qui pourrait être représené sous la forme d'une paire atome /booléen.

    La deuxième raison est que, bien qu'un litéral puisse etre valide quelque soit la valeur du booléen, je ne voudrais sans doute pas que "n'importe qui" aille changer cette valeur "n'importe comment" (autrement, mon atome d'hydrogène risque d'être pris pour une atome d'hélium ) et que je voudrais sans doute m'assurer que cela se fasse "dans les règles"

    Enfin, je me dis que je pourrais parfaitement décider de manipuler une pair atome / booléen pour la représentation réelle aujourd'hui et une structure (non issue de std::pair) demain...

    Si tout le monde n'accède à mon litéral que par un nombre limité de fonctions représentant l'interface publque, je n'aurai que ce nombre limité de fonctions à modifier si je prends une telle décision, alors que si je laisse n'importe qui accéder librement à l'atome et au booléen, j'aurai beaucoup plus d'endroit à aller modifier, sans compter ceux que l'utilisateur aura lui-même créé, et sur lesquels je n'ai aucun pouvoir

    Bon, je t'accorde que je violerais allègrement l'OCP (Open Close Principle) avec cette approche, mais j'aime autant "prévoir le coup"
    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

  11. #11
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    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
    Par défaut
    Citation Envoyé par Steph_ng8 Voir le message
    Bonjour,
    Je vais m'éloigner un peu du sujet, mais j'aimerais avoir quelques précisions.


    Et pour std::pair<T, U> ?
    Les deux données sont publiques, et peuvent être modifiées indépendamment l'une de l'autre, et par n'importe qui.
    Dans ce cas, c'est donc à l'utilisateur qu'il incombe de vérifier que l'invariant est valide, c'est bien ça ?
    Dans le cas où quelle que soit la combinaison des données, l'invariant reste valide, est-ce important/nécessaire de ne pas l'exposer ?

    Un petit exemple concret.
    On dispose d'une classe atome.
    Un littéral est soit un atome (littéral positif), soit la négation d'un atome (littéral négatif).
    Plutôt que de réécrire une classe, j'utilise un std::pair<atome, bool> (en simplifiant).
    Ainsi, si un littéral l est positif (resp. régatif), alors l.second == true (resp. l.second == false).

    Si l'on change la valeur de l'atome sans changer le signe, et inversement, le littéral reste valide et cohérent ; on a simplement changé la valeur du littéral.

    Dans ce cas précis, aurais-tu tout de même utilisé une classe et masqué les données ?
    Dans ce cas précis, tu te retrouve exactement dans le même cas que la classe std::complex : deux valeurs largement indépendantes l'une de l'autre, mais qui, prises dans leur ensemble, signifie quelque chose. Idem pour un vecteur2d, vecteur3d, une matrice, ...

    La notion d'objet vient alors du fait que certains opérations sont définies sur ces valeurs : sans les incorporer dans une classe, tu dois définir ces opérations de manière externe, et les typer faiblement (elle vont accepter tous les arguments du type pair<atome,bool>, même si le bool en question représente autre chose que le signe (par exemple, il peut représenter l'appartenance à un ensemble particulier ; j'en sais rien, je ne suis pas assez calé en math pour comprendre exactement ce que tu dis). Sans avoir typé de manière forte ta pair, tu perds une partie non négligeable de sa sémantique, et cette perte peut entraîner des erreurs au niveau du code en permettant par exemple une utilisation non prévue ou carrément fausse de la valeur.

    Un exemple parmi d'autres : une classe triplet<T> qui définit trois valeurs du type T. Un vecteur3d est un triplet<float>, de même qu'une couleur. Additionner deux triplet<T> n'a du sens que si les deux représente des valeurs issues du même ensemble (vector3d ou couleur), mais le code lui-même n'empêche pas l'addition d'un vector3d et d'une couleur s'il se base uniquement sur triplet<T>.

    Pour autant, ça ne signifie pas nécessairement que les membres de la classe remplaçant pair<atome,bool> doivent être privés. La classe n'a pas d'invariant (autre que l'invariant de la classe atome) car toute valeur est valide. Si la valeur du bool avait dépendu de la valeur de atome (ou l'inverse), alors on aurait eu tout intérêt à les mettre en privé, mais ce n'est pas le cas visiblement dans ton exemple.

    Ceci dit, mettre les valeurs en public expose l'implémentation. Si demain tu décide de changer la façon de stocker l'objet atome, cela aura un impact non négligeable sur tout le code client. En mettant les membres en privé, cela t'autorise à les modifier sans pour autant changer l'interface de la classe. Par exemple (et c'est un exemple volontairement foireux parce que je ne sais pas ce que tu entends par atome).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class litteral
    {
      atome m_atome;
      bool m_sign;
    public:
      const atome& value() const { return atome; }
      bool sign() const { return m_sign; }
    };
    Peut devenir

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    // un litteral dont la valeur dépends de t
    class litteral
    {
      float m_factor;
      bool m_sign;
    public:
      // bien sûr, on ne peut pas renvoyer un const atome&, mais
      // ça change très peu de chose à l'utilisation
      atome value() const { return atome(m_factor, get_current_simulation_time()); }
      bool sign() const { return m_sign; }
    };
    L'interface de la classe ne change pas, malgré le changement d'implémentation. Si les membres sont publics, alors tu forces le code client à faire le calcul à chaque fois. Et si tu utilisais std:::pair, te voilà réduit à changer tout le code client pour t'adapter à la nouvelle représentation.
    [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.

Discussions similaires

  1. Réponses: 7
    Dernier message: 27/02/2012, 17h55
  2. Définitions enum et struct propres à une classe
    Par Kaluza dans le forum Langage
    Réponses: 5
    Dernier message: 26/07/2011, 08h58
  3. Accès aux attributs propres à une classe fille
    Par jamilya dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 24/12/2008, 15h06
  4. Réponses: 1
    Dernier message: 14/07/2008, 11h17
  5. python C API: convertir une struct C en Class python
    Par dmichel dans le forum Interfaçage autre langage
    Réponses: 11
    Dernier message: 25/06/2008, 16h30

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