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 :

Les accesseurs et les détails d'implémentation [Tutoriel]


Sujet :

C++

  1. #21
    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
    Citation Envoyé par gbdivers Voir le message
    Pour la classe de traits, c'est parce que j'aime bien donner le prototype de la classe de traits, pour que celui qui veut spécialiser puisse directement le faire sans aller chercher le code d'une autre spécialisation...
    C'est louable, mais le problème, c'est que si un utilisateur décide d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Point3D<unsigned int> monPoint; // ou n'importe quel autre type pour lequel il n'y a pas de spécialisation
    il n'y a strictement rien qui lui fasse remarquer que la spécialisation n'existe pas, surtout que tu fournis un implémentation pour les fonctions

    Si tu ne donne pas de corps aux fonctions de la version non spécialisée, tu retarde la découverte du fait qu'il n'existe pas de spécialisation pour le type en question au moment de... l'édition de liens (qui peut survenir très tard, en fonction du nombre de fichiers à compiler)

    Par contre, si tu te contente carrément d'une déclaration anticipée de ta classe (qui suffit amplement ), l'erreur arrivera dés le premier fichier qui tentera de créer une instance de ton Point3D, et donc, cela occasionnera du gain de temps pour tout le monde

    mais je peux mettre le code en commentaire
    A vrai dire, c'est carrément tout le corps de la classe (accolades ouvrantes et fermantes comprises) que je mettrais en commentaire
    Merci
    de rien
    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

  2. #22
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    @koala01
    Je me doutais bien qu'aborder le problème des sémantiques aller poser des problèmes

    @Ekleog
    Oui, tu as raison, si on modifie qu'un point, on aura une différence importante
    Pour la spécialisation, on peut sans problème ajouter une nouvelle fonction dans dedans

    @oodini
    As tu lu http://blog.emmanueldeloget.com/inde...C3%A9placement ?

  3. #23
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Je crains aussi que la partie sur les sémantiques complexifie le message -- peut-être, j'avoue parce qu'il s'agit d'un angle d'approche que je n'avais pas encore considéré.

    Quand j'aborde le sujet, les points qui me viennent en premier (et qui sont les plus abordables pour faire passer le message à des non théoriciens du C++), c'est la dichotomie penser services vs penser données. Et que donner accès aux données, c'est dé(en)capsuler l'accès à ces dernières.
    J'aime bien prendre des exemples à base de linge à laver/étendre: dans un monde données, on va à la laverie automatique et on fait tout soit même. Dans un monde objet, on demande à un voisin/pressing/mère si on peut lui confier notre linge, et lui se chargera de savoir comment fonctionne sa machine, ou comment mélanger les diverses affaires.

    S'il y a de la théorie qui me vient en tête quand on parle d'accesseurs & cie, c'est la Loi de Déméter qui présente pas mal de similitudes avec ce côté d'encapsulation.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  4. #24
    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
    @oodini : Pour faire la distinction entre une classe ayant sémantique de valeur et une classe ayant sémantique d'entité, on pourrait dire :

    Si ta classe n'a pas vocation à être dérivée (qu'elle ne servira jamais que dans une agrégation, par exemple), elle peut avoir sémantique de valeur : Deux instances de Point3D peuvent parfaitement avoir des attributs identiques (x = 3.12, y = 14.6 et z=2.222) mais se trouver à des adresses totalement différentes.

    Tu pourrais d'ailleurs créer une autre classe Bipoint dont le seul but est de ... mettre deux points en commun, qui serait utilisée comme membre pour tout ce qui a trait à la mise au point de BoundingBoxes, de politique de contraintes de tailles, etc.

    Cette classe, dont la seule responsabilité est de contenir deux Point3D aurait également sémantique de valeur, car tu peux avoir différents objets qui contiennent un Bipoint dont les attributs sont égaux, et qui se trouvent à des adresses différentes.

    Par contre, si tu introduit la notion de Polygone, tu vas sans doute les dériver en polygone concave et convexe, qui, eux même, pourraient être (ou non) dérivés en
    • trigone
    • quadrone
    • pentagone
    • hexagone
    • ...Nagone
    Quand tu fais du morphing, ce n'est pas une copie du polygone d'origine, mais un clone de celui ci qui est fait.

    Clone qui, au moment de sa création, dispose il est vrai d'attributs totalement identiques à l'objet d'origine.

    La modification du clone peut prendre deux formes différentes :

    Soit tu te contente de modifier un des points du polygone, et, dans ce cas, c'est bel et bien le polygone qui est modifié, preuve supplémentaire que tu as affaire à une classe ayant sémantique d'entité (car tu continues malgré tout à travailler sur le clone du polygone ).

    Par contre, si tu décides de rajouter (ou de supprimer) un point de ton Nagone, là, il faudra voir ce que tu as fait à la base...

    Si tu as fais en sorte que ton polygone puisse contenir "un nombre indéterminé" de points, tu pourras continuer à travailler avec le clone sans grosse difficulté, mais, si tu as décidé de spécialiser ta classe polygone, ton Nagone doit devenir un N+1agone ou un N-1agone, en fonction de ce que tu fais.

    Ce N+1agone ou N-1agone sera un nouveau "clone" de ton Nagone en prenant en compte le point à rajouter / supprimer.

    Une fois que tu as fini la modification de ton polygone "clone", ce que tu feras sera de remplacer le polygone original par... le clone, et ton objet morphé prendra sa nouvelle forme

    On se rend donc compte que nous avons deux comportements très semblables : la copie, et le clonage.

    La copie est autorisée pour les classes ayant sémantique de valeur, car tu peux travailler indifféremment avec l'original ou avec la copie (c'est le cas d'un point, d'une couleur, de tout ce qui permet, en gros, de représenter les "unités mathématiques et physiques courantes".

    Ce sont, classiquement, des classes dont les instances sont constantes : si tu modifies un attribut d'une instance de ces classes, tu obtiens... une autre instance de la classe en question (si tu rajoute "3" à la valeur G d'une couleur RGB, tu obtiens... une autre couleur )

    Dans le cas d'une classe ayant sémantique de valeur, nous pourrions dire qu'il suffit de "faire confiance à ce que l'on voit"...

    30° Celsius, c'est pas 29 °Celsius, 45 Nm/s c'est pas 50, x = 3 y = 4 z=6, c'est pas x = 4 y = 4 z=6, R=12 G=255 B = 16, c'est pas R = 13 G = 255 B = 16 (bon, d'accord, là, on aura du mal à faire la distinction , mais il y a bel et bien une différence )

    Tu peux multiplier à loisir les instances de ces différents exemples, c'est la valeur de leurs attributs qui importe plus que n'importe quoi d'autre.

    Tu peux comparer deux instances de classes ayant sémantique de valeur en comparant leurs attributs deux à deux et décider, si tous les attributs sont égaux, que les deux instances sont égales (30 °Celsius, ca reste 30°Celsius, quelle que soit la région du monde où l'on se trouve et R=12 G=255 B = 16 donnera (toute considération d'ordre purement hardware écartée) la même couleur partout )

    De son coté, le clonage est destiné aux classes ayant sémantique d'entité : tu peux avoir deux instances de la classe présentant un ensemble de caractéristiques identiques, mais tu dois, malgré tout, garder un "facteur discriminant" permettant d'identifier de manière unique et non ambigüe jusqu'à l'original de son clone.

    Tu peux, bien sur, mettre en place un système qui te permettra d'avoir un facteur discriminant "personnel" (comme un système d'identifiant unique), mais, même si tu ne le fais pas, il te reste une solution "offerte" par le système : l'adresse mémoire à laquelle se trouve l'objet.

    En dehors de tout système personnel d'identification unique et non ambigüe que tu pourrais mettre en place, tu pourras toujours faire la distinction entre deux instances d'une classe ayant sémantique d'entité, même s'il s'agit de clone, même si les modifications apportées à l'un ont fait qu'il présente des caractéristiques en tout point identiques à un autre, par... l'adresse mémoire à laquelle ils se trouvent

    A l'inverse des classes ayant sémantique de valeur, ce n'est pas forcément parce que tu change un attribut d'une instance de classe ayant sémantique d'entité que tu crées une nouvelle entité.

    Si tu as dix polygones différents à afficher et que tu modifie la position d'un point de l'un d'eux, tu modifie la forme du polygone, mais l'instance du polygone reste l'adresse mémoire qui était sienne avant la modification.

    Si Quels que soient les mouvements que tu peux faire sur un compte courant, tu identifies de manière unique et non ambigüe le compte et... ca reste le compte de Monsieur Durant

    Même si deux instances présentent des attributs identiques deux à deux, en dehors de tout facteur discriminant personnel, ce n'est pas pour cela que tu pourras utiliser indifféremment une instance à la place de l'autre :

    monsieur Dupont l'aurait mauvaise si, sous prétexte que son compte bancaire présente le même solde que celui de monsieur Durant, tu venais à débiter son compte au lieu de celui de monsieur Durant

    Si tu travailles sur deux polygones dont l'un est le clone de l'autre, tu voudras modifier soit l'original, soit le clone, mais tu ne voudrais pas que les modifications s'appliquent une fois à l'un, une fois à l'autre, de manière aléatoire, en fonction de la direction du vent

    En conclusion, on pourrait dire:

    Qu'une classe ayant sémantique de valeur sera (ordre non trié)
    • généralement non modifiable
    • copiable
    • non héritable
    • comparable par égalité
    • non discriminée (il n'y a pas de facteur discriminant autre que les attributs qui la composent)
    • souvent comparable par "plus petit"
    alors qu'une classe ayant sémantique d'entité sera (ordre non trié)
    • modifiable
    • non copiable, mais éventuellement clonable
    • héritable
    • non comparable par égalité (sauf si présence d'un facteur discriminant personnel)
    • discriminée (même en l'absence d'un facteur discriminant personnel)
    • rarement comparable par "plus petit", bien que certains de ses attributs puissent l'être (sans que ce ne soit une obligation cependant)
    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
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    @koala01
    Là, tu viens de confirmer à oodini que la sémantique est quelque chose de subjectif Ou si c'est pas subjectif, que la distinction est difficile.
    J'avais dit qu'un polygone avait une sémantique de valeur puisque pour comparer 2 polygones, on ne pouvait pas se contenter de vérifier leurs adresses, mais qu'il fallait vérifier les points un par un

    Finalement, la sémantique ne serait-elle pas avant tout un choix du dev, en fonction de comment il aborde la problématique ?

    @oodini
    Par contre, il me semble important de faire le choix et de respecter la sémantique choisie, pour éviter les erreurs (la plus classique, ne pas supprimer la copie d'un classe à sémantique d'entité et la mettre directement dans un vecteur)

  6. #26
    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
    Petite question en passant : est-ce que ces histoires de sémantique de valeur/entité sont utilisées ailleurs que sur dvp.net ? Parce qu'une brève recherche sur google ne m'en a pas donné l'impression.

  7. #27
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    J'ai l'impression que la semantique du type n'a rien a voir avec le sujet.

    Ici, mon point de vue est qu'utiliser un vecteur 3D comme exemple est une très très très mauvaise idée.

    A quoi sert ce type?
    Il donne une information brute. Il n'y a pas de "logique" associée a un vecteur 3D a part les manipulations habituelles qu'on peut faire dessus (transformations, normalisation) et lire les données pour les utiliser d'une façon que le type lui même n'a pas besoin de savoir.

    Dans l'exemple donné, les fonctions proposées m'apparaissent complètement ignorer ce simple fait: la plupart du temps on utilise les vecteur 3D comme donnée brute, abstraites et qui prennent leur sens seulement dans le context d'utilisation.

    Le type lui même n'est là que pour faire un minimum d'abstraction, histoire de pouvoir gérer plus facilement le code mentalement qu'avec un tableau natif.

    Cela reste des données pures, sans semantique, qui sont faites pour etre lues et modifiers, rien d'autre. Avoir des fonctions pour interepreter l'objet est bien beau et meme une très bonne idée, mais il reste que le type lui même n'est même pas censé connaitre ces fonctions.

    Autrement dit, ce qui est suggéré dans l'article est ... "misleading" comme ils disent (c'est quoi l'équivalent français?).

    Il y a peut être des cas ou l'article a raison. Il y a certainement plus de cas ou l'article n'a pas raison. Dans tous les cas, l'exemple est etremement mal choisis.

    Personellement j'ai pratiqué les accesseurs tels que le premier exemple, puis les autres et même des variantes encore plus tordues. Ce que j'en retire c'est que selon les besoins l'utilisation du type va être différente. Un type aussi basic qu'un vecteur ne devrait pas avoir plus de sémantique que représenter des données, tel un int, ou float.
    Même exposer les membres en publique m'apparait tout a fait raissonnable.

    Je travaille beaucoup avec des types a sémantique de valeur qui sont totallement fermées de la façon dont l'article suggère qu'il faudrait qu'ils soient. Un vecteur 3D est beaucoup plus basic dans sa semantique et ne devrais jamais être utilisé pour expliquer cela, parceque les types très basiques sont justement tellement simple qu'ils ne devraient pas porter de sémantique.

    Que ce soit avec accesseur ou avec membres publiques, un vecteur 3D n'est pas plus compliqué qu'un entier et ne devrais jamais être directement associé avec de la logique spécifique, comme par exemple, un système d'affichage.
    L'important est que le type permette de manipuler de la donnée brute. Cela n'a rien a voir avec ce qu'explique l'article, et cela embrouille fortement la discussion autour du sujet.

    Je propose que l'article soit réécris avec un type qui soit plus cohérent avec les arguments donnés, auxquels j'adhére mais pas pour cette catégorie de type.
    Dans l'état actuel, je considère l'article comme étant dangereux, d'un point de vue éducatif.


    Suggestion: un type de coordonnée geographique, un type d'identifiant complexe, etc.

    Des leçons tirées de cette discussion devrait aussi être ajouté à l'article: la sémantique des types dépends de la sémantique propre à l'application ou au domaine qu'elle reproduis; l'existence de sémantique de valeur ou d'entité n'a rien a voir avec le fait qu'une interface simple est difficile à mal utiliser; les types représentant des données brutes ne devraient pas avoir d'autre role que celui ci; etc.


    Cet article m'a chiffoné pendant un moment, mais avec la discussion je vois mieu ce qui ne va pas.

  8. #28
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    @Klaim
    Tu es dur avec mon petit billet de blog

    Je rappelle que le but de cet article est le problème d'exposition des détails d'implémentation interne, ses conséquences et un exemple d'approche pour éviter le problème. La discussion sur les sémantiques s'est greffé dessus après (encore merci koala01 )

    Comme je l'ai déjà dit, en pratique, on utilisera souvent un type POD (donc sans sémantique) pour ce type de structure et on séparera les responsabilités d'affichage dans un classe distinct (respect du SRP). Je voulais pas faire une classe trop complexe pour éviter que la discussion parte sur l'implémentation de cette classe (et ça, c'est loupé), ni nommer mes classes A, B, C...

    Pour autant, je ne pense pas que cet exemple soit "dangereux" et l'on peut tout à fait avoir besoin d'une classe Point3D. Je dirais même que a priori, il ne faudrait pas que manipuler directement le type POD soit le règle, mais plutôt l'exception. Ou alors on revient à du C with class (il est vrai que c'est ce que l'on retrouve souvent pour les applications 3D et jeux)

    @cob59
    Non, une petite recherche avec "value reference semantics" te donnera plein de lien. Par contre, je dois avouer que je ne sais pas d'où vient de concept à l'origine (mais il doit être ancien probablement, au origine de la POO peut être ?)
    EDIT : ah, peut être pas si vieux que ça. D'après http://akrzemi1.wordpress.com/2012/0...lue-semantics/, ça vient de Elements of Programming de Stepanov (le créateur de la STL). Par contre, cela veut peut être dire que c'est un concept plus utilisé en C++ que dans d'autres langages (les C++iens vont encore passer pour des gens qui se prennent la tête avec des détails d'architecture)

  9. #29
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    @Klaim
    Tu es dur avec mon petit billet de blog
    Desolé !


    Citation Envoyé par gbdivers Voir le message
    Comme je l'ai déjà dit, en pratique, on utilisera souvent un type POD (donc sans sémantique) pour ce type de structure et on séparera les responsabilités d'affichage dans un classe distinct (respect du SRP). Je voulais pas faire une classe trop complexe pour éviter que la discussion parte sur l'implémentation de cette classe (et ça, c'est loupé), ni nommer mes classes A, B, C...
    Je comprends bien l'intention, mais le choisir un type qui de toutes façons reviendra à un POD amènera toujours à un conflit entre l'explication et ce qui en sera perçu.
    Il y a des tas d'autres types "simples" qui peuvent servir d'exemple et sont moins abstrait qu'un vecteur 3D. C'est l'exemple le problème, pas l'explication.


    Pour autant, je ne pense pas que cet exemple soit "dangereux" et l'on peut tout à fait avoir besoin d'une classe Point3D.
    Je ne comprends pas cette phrase. Je dis que l'exemple est dangereux parcequ'il "mislead" celui qui le lis en lui faisant croire que c'est une bonne idée de définir un type aussi simple qu'un "point3D" d'une manière plus complexe qu'il n'est nécessaire. Tu noteras aussi que c'est l'exemple typique de type qui est tellement simple qu'on le définis une fois et tout le reste des modifications liés résidera certainemetn dans les fonctions le manipulant, pas dans le type lui même. Ce n'est pas le genre de type que l'on refactor tel que l'exemple le présente. Ce qu'on refactor, c'est ce qui est une sémantique plus complexe qu'un entier, ce qui n'estpas le cas d'un type aussi simple.

    Je dirais même que a priori, il ne faudrait pas que manipuler directement le type POD soit le règle, mais plutôt l'exception. Ou alors on revient à du C with class (il est vrai que c'est ce que l'on retrouve souvent pour les applications 3D et jeux)
    Non, on reviens à de l'orienté donnée, ce qui est supporté par le C++ et tout a fait raisonnable dans un context ou c'est une bonne idée, comme les jeux a haute performance par exeemple.
    Le fait est que dans les boites de jeu vidéo qui ont de bon programmeurs C++, ceux-ci sont tout a fait conscient qu'il n'est pas nécessaire de construire des types "fermés" avec des interfaces extremement réduites pour ce genre de types, parceque ce sont des données brutes et que la sémantique qu'ils représentent n'est pas dans le type lui-même mais dans son utilisation. Autrement, ils auraient un type pour un point sur l'ecran, un type pour la coordonnée physique, un type pour la coordonnée donnée a l'ia, un type pour la coordonnée graphique. C'est inutile, redondant et aussi absurde que d'utiliser des types différents de int pour représenter différents int dans différentes bibliothèques. Sauf si la sémantique peut effectivement changer entre les bibliothèques, auquel cas c'est une bonne idée.

    Dans les boites de jeux le bon programmeur C++ va prendre sa séquence de flotants pour ce qu'ils sont. Ensuite il construira différeentes couches d'abstractions a partir de cette brique, qui seront elles définies tel que le décris l'article.

    Moi je pense que l'exemple est dangereux parcequ'il explique quelque chose de vrai et efficace avec un exemple qui non seulement le déssert mais rends l'argumentation caduque.

    Un point 3D est beaucoup beaucoup trop simple pour être un bon exemple ici. C'est de la donnée brute, pas une voiture ou un polygone.

    Un type représentant une représentation géodésique a plus de sens par exemple.

  10. #30
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Je rejoins Klaim.
    En voyant le titre, je m'attendais plus à une classe dont les getter sont inutiles et exposant une interface. Et dont l'utilisation passerait uniquement par cette interface, mais en aucun cas par des getter.
    En tous cas, l'article m'a surpris, et reste intéressant dans l'ensemble, malgré un exemple mal choisi, qui pourrait selon moi mener à mal comprendre l'article pour un débutant, malheureusement.

    Ensuite, je me rends compte que les getter sont, malgré tout, nécessaires si ce n'est obligatoires, sauf à utiliser friend, voire en cumulant ces 2 choses.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct Points { float x,y,z; };
    struct Triangle { Points pts[3]; };
    struct TriangleDrawer { void Draw(const Triangle& t) { /* ici je dois accéder aux coordonnées xyz de chaque point du triangle */ } };
    Et comment accéder à ces données sans un getter ?
    L'option d'avoir un struct PointDrawer { void Draw(float x, y, z) {} /* ou void Draw(const Points& p) {} */ }; ne m'attirant guère.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #31
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Citation Envoyé par cob59 Voir le message
    Petite question en passant : est-ce que ces histoires de sémantique de valeur/entité sont utilisées ailleurs que sur dvp.net ? Parce qu'une brève recherche sur google ne m'en a pas donné l'impression.
    Non c'est bien plus vieux.
    Si tu veux du forum de référence, ne cherche pas avec google, mais avec google-groups. Tu verras le terme revenir sur usenet (sur clc++m et sur fclc++) depuis pas mal de temps. Dans la FAQ C++lite, etc.

    Par exemple, la forme canonique orthodoxe de Coplien s'applique aux classes à sémantique de valeur.

    Je vois un message dans les archives de clc++ qui avait été conservé dans cpptips: http://cpptips.com/val_sem_eff

    Donc, non, on n'a rien inventé ici. Par contre, il est vrai que c'est une notion que se posent bien plus les développeurs C++.


    Après, je n'arrive pas à retrouver le post qui m'avait donné le nom de quelqu'un que je pensais à l'origine des termes.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  12. #32
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Hum, au final, la question revient donc à savoir l'intérêt d'une classe Point3D. J'ai l'impression que l'on n'est pas d'accord sur ce point.

    On est d'accord qu'un développeur expérimenté se contentera sûrement de créer un type POD et travailler directement avec, sans s'occuper de la sémantique (ou plus précisément, l'expérience fera qu'il saura quelle est la sémantique et ne pas utiliser n'importe comment ses données). Il m'arrive souvent de ne pas rendre mes classes d'entité non copiable (je le fais dans un second temps, en review de mon code)
    (mais dans un contexte multi devs, avec potentiellement des débutants, n'est ce pas une source potentielle de problèmes ?)

    Le problème d'un type POD, c'est que l'on dit en gros "faites ce que vous voulez avec". Et donc potentiellement, n'importe quoi. Or, le dev qui créer ce type POD le fait dans un contexte particulier, pour un usage qu'il a lui même définit. Cette utilisation présente forcement des contraintes (par exemple dans notre cas de Point3D, il ne faut pas que les coordonnées soient de NaN ou Inf). Avoir une classe non POD, avec une sémantique spécifique, permet de cadrer l'utilisation de cet type et garantir que l'on ne puisse l'utiliser que comme le dev le souhaite (interdire un point dont les coordonnées ne sont pas valide).
    La sémantique n'est qu'un moyen permettant au dev de garantir que sa classe sera utilisée d'une certaine manière et pas d'une autre (pour les autres, mais également pour éviter de faire lui même une erreur par distraction)

    Donc, oui, on peut faire un POD (et on verra souvent ça). Mais on se prive alors d'un moyen de sécuriser l'utilisation de la classe

    C'est inutile, redondant et aussi absurde que d'utiliser des types différents de int pour représenter différents int dans différentes bibliothèques.
    Sauf que j'ai déjà lu, pour les mêmes raisons qui justifient de créer une classe Point3D, que l'on pouvait créer des typedef pour préciser l'unité de mesure d'un type. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef float metres;
    typedef float secondes;
     
    metres longueur_piscine, largeur_piscine;
    secondes temps_nageur;
    (mais je ne sais plus où j'ai lu ça, peut être dans Abrahms ou dans un draft sur les user-literals)
    Un code utilisant des typedef précisant localement le contexte et des classes non POD verrouillant l'utilisation faites des données seront plus sur que de simple float[3]

  13. #33
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Hum...
    Certes j'ai lu des morceaux en diagonale, mais je ne vois pas ce que viennent faire les PODs là dedans.
    On peut très bien avoir une classe de données qui contienne une std::string et qui n'a donc rien de POD.

    Après, ces points, sont je pense aussi des mauvais exemples à cause de la sémantique duale que vous avez évoquée (différence entre une donnée brute (un état) et une mesure faite dans un contexte (l'entité)).
    Un peu comme les carrés/rectangles pour le LSP, et autres profs/machines_à_l'école pour le polymorphisme. Ce sont des exemples qui nous détournent très vite des messages à passer.

    D'où mon exemple truqué (*) de service rendu par un truc de la vie courante que tout le monde connait.
    (*) truqué parce que par défaut c'est le mode service qui nous parait naturel, et pas le mode do-it-yourself (aka mode donnée).

    PS: boost.unit c'est bien (pour ces histoires d'int qui représentent des trucs différents). Accessoirement mètre ou watt ne distingue toujours pas la mesure de sa valeur.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  14. #34
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    Hum, au final, la question revient donc à savoir l'intérêt d'une classe Point3D. J'ai l'impression que l'on n'est pas d'accord sur ce point.
    Non, je pense que tu pretes plus de sémantique que nécessaire au type lui même. C'est un type de stockage de donnée, ni plus ni moins, et lui donner plus de fonctionalité que l'accès et le stockage a ces données c'est exactement le meme probleme que de designer un type qui a plusieurs roles.

    On est d'accord qu'un développeur expérimenté se contentera sûrement de créer un type POD et travailler directement avec, sans s'occuper de la sémantique (ou plus précisément, l'expérience fera qu'il saura quelle est la sémantique et ne pas utiliser n'importe comment ses données).
    Non, non, non non non et encore non. Ce n'est pas le sujet.
    Le dévelopeur experimenté va donner un role précis a un type précis.
    Le type dont on parle ici n'a qu'un role de stockage comme je le disais. Ajouter plus ou enlever à une interface d'accès et de stockage pour ce type ne fait que le rendre difficile à utiliser.

    Cela ne veut pas dire qu'on ne peut pas construire d'autres type a partir de celui ci, pour donner une sémantique plus précise, comme lorsque l'on définis un type qui stock des objets et qui est composé de conteneurs.



    Le problème d'un type POD, c'est que l'on dit en gros "faites ce que vous voulez avec". Et donc potentiellement, n'importe quoi.
    Tu peux faire ce que tu veux avec les données contenues dans un vector. Le type vector est la pour le stockage avec une structure memoriel bien définie.

    C'est exactement pareil avec un vecteur/point 3D ou avec un entier, ou encore avec un flotant (qui a une structure bien particulière).

    Le fait qu'un type est un POD dis juste qu'il n'y a pas de contrainte associée en terme de manipulation, ce qui est exactement ce que l'on veut avec un type aussi simple que celui dont on parle.

    Dés le moment ou il y a une contrainte, il est de bon ton de ne pas en faire un POD.

    Même pair est un pod, c'est pas pour rien! Son role n'est pas plus compliqué que de stocker deux valeurs associées. Le role du point 3D est de stocker 3 valeurs associées qui sont des nombres.

    Tout le reste c'est à un niveau d'abstraction supérieur.
    La différence est certes subtile, mais c'est justement cette subtilité qui rends l'article caduque: le type en exemple devrais être un POD ou un équivalent avec accès et stockage et rien d'autre. L'exemple de Bousk est globalement ce que je souleve: le but du type ici n'est pas d'etre associé a une notion d'affichage, ce sont des donnée utilisées pour l'affichage, certainement entre autre, et la donnée n'est pas censé savoir a quoi elle sert.

    C'est finalement rare d'avoir a définir de tels types, mais c'est pourtant nécessaire.


    Or, le dev qui créer ce type POD le fait dans un contexte particulier, pour un usage qu'il a lui même définit. Cette utilisation présente forcement des contraintes (par exemple dans notre cas de Point3D, il ne faut pas que les coordonnées soient de NaN ou Inf).
    Cela n'est pas toujours vrai, en particulier pour ce genre de type. Dans le cas d'une application particulière, redéfinir un type qui encapsule un vecteur3D est une meilleure idée.

    Encore une fois, le choix du type embrouille le sens de l'article.

    Avoir une classe non POD, avec une sémantique spécifique, permet de cadrer l'utilisation de cet type et garantir que l'on ne puisse l'utiliser que comme le dev le souhaite (interdire un point dont les coordonnées ne sont pas valide).
    Toutes les règles ne s'appliquent pas à tous les cas. C'est ce que j'essaie d'expliqué: tu as choisis un cas "exceptionel"...

    La sémantique n'est qu'un moyen permettant au dev de garantir que sa classe sera utilisée d'une certaine manière et pas d'une autre (pour les autres, mais également pour éviter de faire lui même une erreur par distraction)

    Donc, oui, on peut faire un POD (et on verra souvent ça). Mais on se prive alors d'un moyen de sécuriser l'utilisation de la classe

    Dans le cas que tu décris dans l'article, il est plus interessant de faire un pod puis un type particulier qui ajouter une couche de sémantique.


    Sauf que j'ai déjà lu, pour les mêmes raisons qui justifient de créer une classe Point3D, que l'on pouvait créer des typedef pour préciser l'unité de mesure d'un type. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef float metres;
    typedef float secondes;
     
    metres longueur_piscine, largeur_piscine;
    secondes temps_nageur;
    (mais je ne sais plus où j'ai lu ça, peut être dans Abrahms ou dans un draft sur les user-literals)
    Un code utilisant des typedef précisant localement le contexte et des classes non POD verrouillant l'utilisation faites des données seront plus sur que de simple float[3]

    Ce cas est un gros piège et risque de détourner la discussion, mais je t'invite a voir std::chrono pour réaliser qu'au final ce n'est pas une bonne idée de faire cela avec des typedefs, meme si c'est suffisant pour une implémentatoin "simple" dont la sémantique n'a pas grand effet sur l'application.

  15. #35
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    @Bousk
    Ce cas est, je pense, exactement un cas d'utilisation acceptable de friend.

    Pour faire un drawble, on aura en effet besoin d'avoir accès au tableaux de coordonnées (float[3] pour un point, voir float[N] pour un buffer).
    Une solution est d'exposer pour toutes les classes représentant un objet 3D composé de Point3D une fonction permettant de récupérer ce tableau. Voir faire un god-object avec une fonction pour récupérer le tableau (oh mon dieu, un god-object, quelle horreur).
    Avec un friend, on peut avoir une classe dédiée qui permet de récupérer le tableau et qui sera friend. Cette solution me semble préférable, puisque l'on ne pollue pas l'interface des classes avec une fonction qui n'ont rien à voir avec la sémantique de l'objet manipulé (quand on fait des manipulations géométrique sur un triangle en 3D, on se moque un peu que ce triangle soit affichable, qu'il soit lisible et enregistrable sur un fichier, sérialisable sur le réseaux, etc.) De plus, on garde la possibilité de déterminer le type de fonction GL à appeler dans cette fonction (comme présenté avec les templates dans l'exemple)


    EDIT : bon, je vois que beaucoup bloque sur mon exemple de Point3D
    Je réfléchirais à tête reposée dessus et verrais s'il est nécessaire de changer l'exemple pour faciliter la compréhension... ou pas

  16. #36
    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 705
    Points
    2 705
    Par défaut
    Saperlipopette, voilà un débat bien passionnant.

    J'ai un peu contribué à l'embrasement de la situation, mais je n'ai malheureusement pas le temps de lire vos (longues) contributions.

    I will be back.

  17. #37
    Invité
    Invité(e)
    Par défaut
    Salut,

    la semantique du point c'est un peu au plaisir de chacun.
    Certains peuvent voir le point comme un objet geometrique, qu'on translate, rotate, additionne (geo affine / vecteur), homothetise, etc...

    D'autres comme une vulgaire structure de donnees.

    Je pense que l'exemple d'une classe laisse presager l'emploi de la premiere option, la seconde etant implementee avec des attributs publiques, ou meme un simple typedef.

    Quoiqu'il en soit, c'est aussi misleading a mon gout. Quand je vois class, c'est dans la majorite des cas pour faire du business, donc autant lever l'ambiguite avec un exemple explicite tel qu'un record en bdd, un tuple boost, ou autre.

    Quand a draw sur un point...tu as toi meme dit que dans ce cas la, il fallait appeler la class drawablePoint, il y a anguille sous roche

  18. #38
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    @Bousk
    Ce cas est, je pense, exactement un cas d'utilisation acceptable de friend.
    Je suis d'accord pour un Drawer, le déclarer friend, mais si tu en as plusieurs, il faudrait alors déclarer chaque Drawer comme friend, et du coup ça limite l'intérêt.
    Mais ça ajoute le "problème" que la classe Point doit connaître son Drawer (qui peut ne pas être un problème).
    Si à chaque ajout d'un Drawer tu dois modifier la classe Point pour déclarer le nouveau Drawer comme friend je trouve que ça va à l'encontre de l'OCP et à ce moment il vaut mieux un getter amha.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  19. #39
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    std::pair n'est pas un POD. Cela dépend de ce qu'il va y avoir dessous.
    Une paire de std::string ne peux pas être POD.

    POD, OSEF. Cela veut juste dire que le type est manipulable en C. La notion qui vous intéresse, c'est la notion d'objet qui n'est qu'un agrégat de données. -> Chez les Javaistes qui réfléchissent à la question des getters & cie, ce sont des Data Objects (ou DTO peut-être ... ? -> http://www.artima.com/forums/flat.js...6&thread=36312)
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  20. #40
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    576
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 576
    Points : 1 528
    Points
    1 528
    Par défaut
    C'est marrant, personnellement en lisant l'article j'aurais tout fais sauf mettre une méthode draw(). Je ne vais pas tergiverser sur le fait de donner une responsabilité ou pas à la classe, mais pour moi il s'agit plus d'un problème d'interfaçage de 2 API.

    On a d'un coté glVertex, une API qui à besoin d'un PointGL par exemple, mais nous manipulons des Point3D. Le service à fournir serait de pouvoir "convertir" un Point3D en PointGL. Je suppose que des Design Pattern de ce type existent, mais pour rester simple et didactique, j'aurais rajouter une méthode du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class Point3D
    {
      void toFloat(float& x, float& y, float& z);
    }
    En 3D une technique assez répandu est de surcharger l'operateur de cast (float*) pour utiliser une class Point3D maison avec les fonctions du type glVertex*fv. Si le point est implémenté avec des double, il suffit de faire une copie des coordonnée dans un buffer de float. Catastrophique pour les perf, mais complétement transparent à l'utilisation.
    La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer. - Antoine de Saint-Exupéry

Discussions similaires

  1. Réponses: 4
    Dernier message: 11/09/2006, 16h55
  2. Les polices dans les tables et les requêts
    Par zooffy dans le forum Access
    Réponses: 3
    Dernier message: 21/06/2006, 11h06
  3. Outils pour creer les accesseurs et les mutateurs
    Par MarieMtl dans le forum MFC
    Réponses: 3
    Dernier message: 03/10/2005, 17h03

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