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 :

Pointeurs / Références / Héritages -> besoin de précisions


Sujet :

C++

  1. #1
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut Pointeurs / Références / Héritages -> besoin de précisions
    Bonjour à tous,

    Comme vous pouvez le deviner, j'ai une question sur le C++. Notamment sur les pointeurs / références et héritages.
    Un moment, j'ai cru qu'il fallait toujours utiliser les pointeurs pour utiliser les classes que nous héritions. Ainsi, nous pouvions faire une liste de pointeur sur la classe mère qui entrainait l'appel à la fonction hérité des sous classes, si disponible, selon le vrai type "qui se cache derrière le pointeur générique" (si je puis dire).

    Hum, je ne sais pas trop comment énoncé la question et en fait, je ne suis même pas sur d'avoir une question sur ce point. Bref passons (certes, c'est encore un peu le fouillis dans ma tête).

    J'énonce souvent une règle (que je puisse avoir entendu sur ce forum) qui est d'éviter à tout pris les pointeurs (entre autre, car c'est nous qui gérons la durée de vie des objets). Le mieux étant d'utiliser des smart pointeurs comme ceux de boost.
    Mais, je voulais savoir, lorsque nous avons une classe qui contient une instance d'une autre classe. Par exemple, une classe Renderer qui contiendrai une Camera.
    Si en dehors de ma classe Renderer, j'ai besoin de modifier la camera, faut il mieux que je fasse un setter qui retourne un pointeur ou une référence? (Dans les deux cas, je ne retourne pas quelque chose de constant ... ce qui m'embête un peu).
    En fait, si vraiment la classe Renderer devait garder le controle complet de la camera, il ne faudrait même pas que je fasse de setter, mais qu'à la place je réimplémente des fonctions, qui appellerai celle de la classe camera. N'y a t'il pas un design pattern pour me simplifier ce processus?

    Finalement, si j'utilise un std::vector<T> de mon objet. Dois-je stocker des pointeurs ou dois-je essayer de faire sans les pointeurs ?
    Il me semble que le seul cas ou je suis vraiment forcé d'utiliser les pointeurs, ces lorsque la classe que je veux mettre dans mon vecteur est abstraite pure, ou du moins, lorsque c'est une classe mère et que je veux une liste de ceux-ci pour appeler les méthodes hérités facilement. Ai-je juste?

    Merci de m'éclairer sur ces points qui me mettent souvent en doute.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,

    Citation Envoyé par LittleWhite Voir le message
    Un moment, j'ai cru qu'il fallait toujours utiliser les pointeurs pour utiliser les classes que nous héritions. Ainsi, nous pouvions faire une liste de pointeur sur la classe mère qui entrainait l'appel à la fonction hérité des sous classes, si disponible, selon le vrai type "qui se cache derrière le pointeur générique" (si je puis dire).

    Hum, je ne sais pas trop comment énoncé la question et en fait, je ne suis même pas sur d'avoir une question sur ce point. Bref passons (certes, c'est encore un peu le fouillis dans ma tête).
    Deux points :

    L'héritage suppose une sémantique d'entité et une sémantique d'entité est incompatible avec la copie. Donc, un objet d'une telle classe, étant non copiable, est naturellement manipulé par pointeur ou par référence lorsqu'il traverse des fonctions ou d'autres objets.

    Ensuite, très concrètement, avec un typage statique comme le C++, pour utiliser le polymorphisme d'inclusion, une expression doit utiliser une variable dont le type dynamique et le type statique peuvent différer (Type statique et type dynamique). En C++, seul les pointeurs et les références peuvent avoir un type dynamique différent du type statique.

    Citation Envoyé par LittleWhite Voir le message
    J'énonce souvent une règle (que je puisse avoir entendu sur ce forum) qui est d'éviter à tout pris les pointeurs (entre autre, car c'est nous qui gérons la durée de vie des objets). Le mieux étant d'utiliser des smart pointeurs comme ceux de boost.
    Je ne comprends pas la règle comme étant il faut éviter à tout prix les pointeurs. Mais plutôt :
    1/ Une classe doit avoir une responsabilité unique (SRP).
    2/ Gérer un pointeur, c'est compliqué ( robustesse face aux exceptions, politique de partage, détruire au bon moment, etc.) : c'est une responsabilité à part entière.
    Conclusion :
    Une classe qui doit gérer une ressource pointeur doit déléguer cette responsabilité à une classe dédiée (un pointeur intelligent, un std::vector, etc) sans quoi elle serait amené à multiplier les responsabilités.

    En revanche, un shared_ptr est souvent dégainé avec une grande facilité, pour ne pas dire par paresse, parce qu'on a fait l'économie en phase design de définir le rôle exact lié au pointeur (simple association, agrégation ou composition).

    Citation Envoyé par LittleWhite Voir le message
    Mais, je voulais savoir, lorsque nous avons une classe qui contient une instance d'une autre classe. Par exemple, une classe Renderer qui contiendrai une Camera.
    La camera est-elle un membre de Renderer ou est-elle un paramètre d'une fonction d'exécution du rendu de Renderer ? Un indicateur de cohérence d'une classe consiste à mesurer l'utilisation d'un membre au regard de l'ensemble des fonctions publiques de la classe. Plus cette fréquence est élevée, plus le membre est pertinent. A l'inverse, si le membre n'est utilisé que dans une fonction, probablement est-il plus pertinent que ce soit un paramètre.

    S'il s'agit d'un membre de la classe, reste à identifier :
    1/ Les durées de vie du conteneur et du contenu sont elles fortement liées (composition) ? le contenu peut-il être partagé entre différents conteneurs (aggrégation) ? le lien contenu/conteneur est-il encore plus lâche (association) ?
    2/ Le contenu a-t-il une sémantique d'entité ou de valeur ?
    3/ Comment est créé l'objet membre (dependance injection) ?

    Citation Envoyé par LittleWhite Voir le message
    Si en dehors de ma classe Renderer, j'ai besoin de modifier la camera, faut il mieux que je fasse un setter qui retourne un pointeur ou une référence? (Dans les deux cas, je ne retourne pas quelque chose de constant ... ce qui m'embête un peu).
    En fait, si vraiment la classe Renderer devait garder le controle complet de la camera, il ne faudrait même pas que je fasse de setter, mais qu'à la place je réimplémente des fonctions, qui appellerai celle de la classe camera. N'y a t'il pas un design pattern pour me simplifier ce processus?
    Un design pattern, non. Mais qui dit lien entre deux objets, ne dit pas forcément composition ou agrégation. L'association suffit peut être. Au quel cas, Renderer et Camera ne sont pas aussi fortement couplés et permet que Caméra et XXX soit aussi couplés sans passer par Renderer.

    Un setter est une mauvaise idée (ne serait-ce que forcément tu vas violer la pauvre Démeter), retourner un pointeur/référence non constant sur un membre a raison de te déranger (c'est d'ailleurs souvent interdit dans les règles de codage)

    Citation Envoyé par LittleWhite Voir le message
    Finalement, si j'utilise un std::vector<T> de mon objet. Dois-je stocker des pointeurs ou dois-je essayer de faire sans les pointeurs ?
    Il me semble que le seul cas ou je suis vraiment forcé d'utiliser les pointeurs, ces lorsque la classe que je veux mettre dans mon vecteur est abstraite pure, ou du moins, lorsque c'est une classe mère et que je veux une liste de ceux-ci pour appeler les méthodes hérités facilement. Ai-je juste?
    Pointeur ou référence vont être le moyen naturel/obligatoire du langage pour répondre à un besoin de conception : sémantique d'entité (donc héritage que la classe de base soit abstraite ou pas), association/agrégation, dissociation construction membre/objet, etc.

  3. #3
    Membre du Club
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    28
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 28
    Points : 41
    Points
    41
    Par défaut
    Intéressante question qui me préoccupe aussi. Merci 3DArchi pour ta réponse précise.

    Pour être sur de bien différencier les 3 designs :
    Citation Envoyé par 3DArchi Voir le message
    simple association, agrégation ou composition
    Est-ce que c'est bien cela ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    //composition
    class B : A {
    }:
     
    //agrégation
    class B {
    A member;
    };
     
    //association
    class B {
    void function (const A& a);
    };
    Dans le cas de la caméra et du renderer. Je dirais qu'un renderer peut avoir plusieurs caméras (par exemple un soft 3D a différentes vues de face, côté etc...) et je me dirigerais vers l'association (cf. ma vision de l'association plus haut).

  4. #4
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Bonjour,

    Citation Envoyé par 3DArchi Voir le message
    Un setter est une mauvaise idée (ne serait-ce que forcément tu vas violer la pauvre Démeter), retourner un pointeur/référence non constant sur un membre a raison de te déranger (c'est d'ailleurs souvent interdit dans les règles de codage)
    En même temps, si la loi de Démeter protège le concepteur de la classe de l'indiscrétion de ses utilisateurs, elle contraint surtout l'utilisateur à être intrusif pour procéder à des ajouts de fonctionnalités. A mon sens, son application aveugle, en particulier sur des briques de base, induit une trop grande suspicion sur l'utilisation des classes du système : Rien de bon en terme de ré-utilisabilité.


    Plutôt que d'appliquer bestialement des règles, il vaut mieux comprendre ce qu'implique le non respect de ces règles. Je vais essayer de préciser les implications du non respect de règles, vous m'éclaircirez sûrement si je me fourvoies (en trollant, on progresse plus qu'en se cachant ).

    Qu'implique l'accès publique à un membre (le mal absolu)?

    Si on donne l'accès publique à un membre "x" sur une classe "Point", on se prive de tout refactoring vers une autre représentation interne.

    On se prive de pouvoir passer de :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Point {
    public:
    	double x;
    	double y;
    };
    à

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class Point {
    public:
    	Coordinate coordinate;
    };
    Autant dire que ça n'est pas très souple

    Qu'implique l'accès en référence const et non const à un membre (intermédiaire)

    A mon sens, l'accès par référence non constante est un compromis entre l'accès public à un membre et l'accès par un setter classique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class Point {
    public:
     
    	inline const double & x() const { return _x; }
    	inline double &       x() { return _x; }	
    	inline const double & y() const { return _y; }
    	inline double &       y() { return _y; }
     
    private:
    	double _x;
    	double _y;
    };
    On peut :
    - modifier la représentation interne (passer _x,_y en _coordinate)

    On ne peut pas :
    - mettre par la suite une logique lors de la modification (par exemple, pré-calculer la norme lors de setX)
    - contrôler la cohérence interne de la représentation (A prohiber sur un interval min,max par exemple)

    Pour les adeptes des langages objets où tout est référence et où la notion de const est absente, cette problématique revient à la question : Mon getter doit-il renvoyer un clone ou pas? (Tous les getters Java ne renvoyant pas de clone sont équivalents à l'approche du const/non const)

    Qu'implique l'accès en getter constant (readonly) et setter

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Point {
    public:
     
    	const double & getX() const { return _x; }
    	void 		   setX( const double & x ) { _x = x; }
     
    	const double & getY() const { return _y; }
    	void 		   setY( const double & y ) { _y = y; }
     
    private:
    	double _x;
    	double _y;
    };
    On peut :
    - changer la représentation interne

    On ne peut pas :
    - Modifier sans remplacer (sans procéder à des copies)

    Est-ce donc la panacée? Ceux qui laissent l'accès en modification sont-ils des fous furieux : je ne pense pas. S'il y a aucune raison valable de protéger l'accès en modification : Autant le fournir pour simplifier la vie des utilisateurs.


    Pourquoi Demeter? A mon humble avis, parce-que le problème est souvent mal posé avec une approche purement locale des relations entre classes : Le cas du Renderer référençant la Camera est typique. On ne veut pas à juste titre que l'utilisateur fasse :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    renderer.getCamera().setPosition( position );
    Mais le code ci-après sera tout aussi paumant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::auto_ptr< Camera > camera( renderer.getCamera().clone() );
    renderer.setCamera( camera.release() );
    L'origine du mal : La relation directe entre le Renderer et une classe Camera n'a pas raison d'être, on cherche donc à tout prix à la masquer aux utilisateurs de la classe Renderer et on la virera probablement en cas de refactoring pour du multi-camera comme l'indique arthurG.


    <troll>Demeter dans son approche interdisant le chaînage est un cache misère en cas de relation de voisinage direct qui n'ont pas lieu d'être</troll>

    A mon humble avis, il existe une approche plus viable : Centraliser l'accès aux éléments de sorte que le parcours des liens aient une signification. Cette approche revient à limiter le nombre de voisin direct aux seuls éléments qui composent la classe et à un point d'accès vers les principales classes du système (les fabriques, les paramètres, le système de log, etc...)


    En guise d'exemple, dans le cas d'un système de rendu, on pourrait introduire la notion de "monde" fournissant l'accès aux différents éléments du système de rendu. Chaque élément du système de rendu à accès à World (sans l'exposer). Tous les éléments du système sont accessibles en descendant les relations à partir de World.

    Que devient l'accès aux composants du système :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    World world;
    //acces en modification a la camera
    world.getCamera().setPosition( Point(4.0,6.0) );
    //acces en remplacement de la camera (fabrique pour passer world au constructeur)
    CameraFactory & cameraFactory = world.getCameraFactory();
    world..setCamera( cameraFactory.newTrackingCamera(idObjet) );
    Que devient le renderer (sans singleton, en passant sous silence une éventuelle fabrique de Renderer):

    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
     
    class Renderer : public WorldEntity {
    public:	
    	Renderer( World & world ):
    		WorldEntity(world)
    	{
    	}
     
     
    	void render() {
    		Camera & camera = world().getCamera();
    		//rendering
    	}
     
    };

    Qu'est-ce que l'on perd en possibilité de refactoring : Pas grand chose voir rien :
    - Si on déporte la caméra sur un Viewer, il suffira de transformer l'accès à la camera dans la classe World
    - Si on met en place un système multi-caméra, il suffira de renvoyer la caméra active dans getCamera.

    On y gagne même beaucoup au final car les voisins direct que l'on masquait avec demeter disparaissent.


    En somme, plutôt que de s'obstiner à priver l'utilisateur du chaînage, ne vaut-il pas mieux le guider dans un chaînage intelligent partant d'un point d'accès central (ci-avant World) en fournissant des relations qui aient un sens?

    Que pensez vous de cette approche?

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

    Informations professionnelles :
    Activité : aucun

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

    Aggrégation :
    relation "contenant à contenu" qui existe entre deux classes dans laquelle un contenu peut être lié à plusieurs contenant.

    Typiquement, nous serions proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Contenant
    {
        private:
            Contenu * ctn;
            // voir
            Collection < Contenu *> collection; // Collection: std::vector, par ex
    };
    Composition :
    Relation "contenant à contenu" qui existe entre deux classes dans laquelle le contenu ne peut pas subsister si le contenant est détruit.

    Typiquement, cela se représente sous la forme de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Contenant
    {
        private:
            Contenu  ctn;
            // voir
            Collection < Contenu > collection; // Collection: std::vector, par ex
    };
    Enfin, l'association permet "simplement" de faire "travailler de concert" deux types distincts, parce que l'un (celui au départ duquel on invoque une fonction / un comportement) a "besoin" du comportement offert par l'autre, ou parce que le premier "prend la responsabilité" d'invoquer un certains nombre de comportements du deuxième selon une logique clairement définie.

    Si l'objet utilisé dans la fonction est susceptible d'être différent en fonction des différents endroits où la fonction est appelée, cela se traduira souvent par le passage de l'objet sous la forme d'un argument

    L'héritage quant à lui implémente une relation de généralisation / de spécialisation.

    Soit parce que l'on peut considérer qu'un objet du type dérivé EST UN objet du type de base dont certains comportements sont adaptés au type dérivé (fonctions virtuelles), comme c'est le cas pour l'héritage publique (tu peux alors décider d'utiliser n'importe quel objet du type dérivé lorsque tu t'attends à manipuler un objet du type de base), soit tu considère que ton type dérivé agit en interne "un peu comme" le type de base, mais que l'interface du type de base n'est pas "tout à fait adapté" aux besoin du type dérivé.

    Nous sommes là à un niveau de dépenance bien plus important que les différentes relations dont j'ai parlé plus haut
    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
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par arthurG Voir le message
    Est-ce que c'est bien cela ?
    Pas tout à fait. Comme le dit Koala, composition, agrégation et association sont trois intensité de lien différents entre 2 objets allant du plus engageant (la composition) au moins engageant (l'association). L'héritage privé peut être utilisé pour la composition mais ce n'est pas toujours pertinent. Un membre pointeur ou par valeur peut aussi être utilisé (si nécessité d'allouer sur le tas, d'utiliser du polymorphisme, d'avoir une création non présente dans la classe, etc.). Pour l'agrégation ou l'association, il est vrai que ce sera plus probablement un pointeur puisque les durées de vie (et à travers ça le couplage) sont sensées être disjointes.


    Citation Envoyé par bretus Voir le message
    Que pensez vous de cette approche?
    C'est une très intéressant réponse. J'essaie de trouver le temps de te répondre plus longuement dans le w.e. en particulier :
    - sur les aspects getter/setter qui reviennent à poser la question de la définition d'une classe et pourquoi l'amitié peut alors avoir un sens (sérialisation, builder)
    - sur les aspects Demeter : ou quand une rupture de style ou d'un loi (tout comme son artificialité dans son utilisation) reflète plus un problème d'architecture et de conception d'abord.
    - sur les aspects évolutions et reuse
    Mais je sens à ta réponse que nous somme globalement d'accord sur le pelage du troll

  7. #7
    Membre du Club
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    28
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 28
    Points : 41
    Points
    41
    Par défaut
    Merci pour les précisions koala01 et 3DArchi. Je me fourvoyais complètement.
    C'est le genre de threads utiles, j'attends la suite avec impatience

  8. #8
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Bonsoir,

    @bretus: Première réaction "à chaud" je compléterais surment mon point de vue plus tard.

    1. AMHA, dans les 3 cas que tu preséntes (publique/getter non-const et const/getter+setter), la possibilité de changer la représentation interne n'est pas loin d'être une chimère. En effet le fait de retourner une référence implique que l'objet doit exister avant l'appel de la fonction. En clair oui on peut passer à une représentation interne avec une classe de type Coordinate si celle-ci a un interne 2 composantes et permet d'y accéder (*). Pour faire simple on ne change pas la représentation, on introduit un wrapper qui n'a aucun interet si il sert à représenter l'implémentation (**).

    2. La loi de Demeter peut sembler restrictive dans ses différentes formulations, je pense qu'il est plus pertinant de comprendre ce qu'elle cherche à limiter : La dépendance d'une classe vis-à-vis de classe (***) qui apparaisent dans l'implémentation et pas dans l'interface. Ce qui est raisonnable et permet au "découpage" OO du programme d'être efficase (si trop de telle dépendances existent le découpage est purement articifiel, une modification d'une classe entraine des modifications à des endroits qui devraient être indépendants).

    3. Ce que tu proposes avec ta classe World semble interessent. Cependant j'ai l'impression que ca invite trop facilement à la création d'un God-Object, et même pire : une sorte d'utilisation d'une classe comme namespace qui contient des variables globales (presque un gros singleton ?) mais je pense avoir manqué un point de ton raisonnement


    (*) Je pars du principe que l'interface ne change pas, et donc tes setters/getters gardent la même signature même si la représentation interne change. Sinon on se retrouve plus directement dans le cas 1 : un changement de représentation interne créé un changement d'interface.

    (**) Ca peut servir comme type de retour d'une fonction membre de cette classe à destination de l'utilisation, mais en interne ca n'apporte rien AMA.

    (***) Je ne considère ici que les classes métiers (ie celle qui interviennent dans l'architecture même) et pas les différentes classes à visées plus technique (typiquement les pointeurs intelligents).

  9. #9
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    @arthurG: Je suis d'accord, c'est un fil de discussion important, notamment car le C++ est dur à maitriser.

    Je n'ai pas encore lu vos réponses (faute de temps). Mais pour apporter des précisions à mon histoire de caméra:
    Le Renderer possède une camera (donc, une camera est membre de la classe Renderer). Mais, un utilisateur peut volontairement bouger la camera. Donc, il me faut soit un accès à la caméra, soit un accès à des fonctions du Renderer qui bougeront la camera.
    La solution que j'ai choisie est:
    Le Renderer à un getter de camera, qui retourne une camera constante.
    Le Renderer à aussi un setter de camera.
    L'utilisateur get la camera, en fait une copie (vu que je retourne une référence constante), modifie la copie et réinjecte la copie modifiée dans le Renderer.

    Est ce propre, une bonne chose à faire ? (moi je trouve que cela embête un peu l'utilisateur qui veut déplacer la camera) (et qu'il y a une copie d'un élément, alors que ma classe à une sémantique d'entité (si j'ai bien compris). Donc je suis dans le faux? (ce sont des concepts avec lesquels je dois encore m'habituer (et lire tout ce que vous avez dit)).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  10. #10
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    1. AMHA, dans les 3 cas que tu preséntes (publique/getter non-const et const/getter+setter), la possibilité de changer la représentation interne n'est pas loin d'être une chimère. En effet le fait de retourner une référence implique que l'objet doit exister avant l'appel de la fonction. En clair oui on peut passer à une représentation interne avec une classe de type Coordinate si celle-ci a un interne 2 composantes et permet d'y accéder (*). Pour faire simple on ne change pas la représentation, on introduit un wrapper qui n'a aucun interet si il sert à représenter l'implémentation (**).
    Juste remarque, tu n'as pas une liberté totale de changer ta représentation interne. Tu dois avoir accès à une instance d'un double depuis point dans l'exemple. Tu ne peux pas mettre un int par exemple, ou en représentation polaire r,theta. Mais souvent tu as une marge de manoeuvre suffisante.

    Pour l'intérêt, ça ne se limite pas à la possibilité d'introduire un wrapper. Ca te permet de déporter l'instance concrète (par agrégation ou héritage)

    Citation Envoyé par Flob90 Voir le message
    2. La loi de Demeter peut sembler restrictive dans ses différentes formulations, je pense qu'il est plus pertinant de comprendre ce qu'elle cherche à limiter : La dépendance d'une classe vis-à-vis de classe (***) qui apparaisent dans l'implémentation et pas dans l'interface. Ce qui est raisonnable et permet au "découpage" OO du programme d'être efficase (si trop de telle dépendances existent le découpage est purement articifiel, une modification d'une classe entraine des modifications à des endroits qui devraient être indépendants).
    Attention, on est d'accord avec (***). En gros, je la trouve plutôt judicieuse pour les modèles métiers haut niveau qui sont utilisés directement dans l'application.
    Pour être clair, les éléments du moteur de rendu doivent pouvoir parcourir librement les liens entre les différents composants qui forme le moteur de rendu. Sans cela, en s'efforçant de respecter Demeter, quand tu mets en place un Renderer3D tu ajoutes 150 fonctions utilitaires pour respecter Demeter, quand tu ajoutes le Renderer2D, 100 autres et au final : Tu t'y paumes. En gros, tu remplaces la complexité des liens par un trop grand nombre de fonctions utilitaires (où ton aptitude à trouver des noms qui aient un sens est mise à rude épreuve).

    Citation Envoyé par Flob90 Voir le message
    3. Ce que tu proposes avec ta classe World semble interessent. Cependant j'ai l'impression que ca invite trop facilement à la création d'un God-Object, et même pire
    Un indice : World est en paramètre du Renderer, ça serait un peu fou pour un singleton. World a aucune raison d'être unique pour le processus.

    Au niveau God-Object, World à pour rôle bien définit : Centraliser l'accès aux principaux composant.

    Après, il faut composer entre le dogme et l'aspect pratique. Quand tu as world ou équivalent, même s'il pue la classe déesse : C'est pratique. Imagine que tu rendes ton application pluggable ou scriptable, tu as un seul élément de contexte à fournir : World.

    Enfin, niveau lisibilité de l'architecture, c'est à mon sens plutôt bénéfique comme approche dans la mesure où sans t'en rendre compte, tu hiérarchises les liens à partir de World, avec une approche globale (comment décomposer mon monde en sous-partie?) et non locale (de quoi j'ai besoin au niveau de cette classe?).

    Accessoirement, cette hiérarchie te simplifie la vie en terme de gestion de la mémoire (Si je ne dis pas de connerie, c'est l'approche Qt où le père détruit les fils).


    ++,
    merci d'avoir pris le temps de répondre

  11. #11
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Bonsoir,

    1. J'ai peut-être un peu exagérer en disant que ca ne servait à rien, par contre je maintiens que ca ne permet pas de réel changement de représentation interne : tu as beau avoir un sous-objet de type Coordonnees, la donnée interne est nécessairement un couple de double. Coordonnees n'est donc qu'un intermédiaire, ca peut être utile sur d'autres points : type de retour, découpage du code mais rien en ce qui conscerne le changement de représentation interne. Je ne vois pas où il y aurait introduction d'une marge de manoeuvre.
    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
     
    struct A
    { /*...*/ };
     
    struct B
    { 
      /*...*/ 
      A& get() { return a; }
      private:
        A a;
    };
     
    struct C1
    {
      A& get() { return a; }
      void process()
      { /*algo complexe avec un A mais simple avec un B*/}
      private:
        A a;
    };
     
    //Même que C1 mais représentation interne changée
    struct C2
    {
      A& get() { return b.data(); }
      void process()
      { /*algo simple avec b*/ }
      private:
        B b;
    };
    Dans ce code la représentation interne n'a absolument pas changée, c'est toujours un A, ce qui est gagné par B c'est une délocalisation du code complexe sur A dans les fonctions de la classe B (non écrites). Je suis totalement d'accord que ca peut être avantageux, mais l'accesseur nous contraint quand même sur la représentation interne.

    2. Après avoir relu ton message je pense qu'on était en fait d'accord sur ce point.

    2/3. Il faudrait que j'approfondise plus tes exemples Renderer/World, je me suis pas encore penché sur ton architecture, ce que je disais étaient seulement des impressions (que j'ai toujours).

    NB: J'ai bein vu que ce n'était pas réelement un singleton ni un god-object (j'ai écrit "presque un gros singleton" et "invite ... à la création de god-object")

    PS: L'architecture de Qt est historique, elle viole clairement le SRP (God-Object), pas certain que cette approche serait utilisée si Qt était codé aujourd'hui. Cependant oui ca marche (surment la raison pour laquelle Qt ne change pas son architecture, pourquoi changer queque chose qui marche ?), mais on peut faire autrement. Il y a déjà eu un débat sur ce sujet sur le forum

  12. #12
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    L'utilisateur get la camera, en fait une copie (vu que je retourne une référence constante), modifie la copie et réinjecte la copie modifiée dans le Renderer.

    Est ce propre, une bonne chose à faire ? (moi je trouve que cela embête un peu l'utilisateur qui veut déplacer la camera) (et qu'il y a une copie d'un élément, alors que ma classe à une sémantique d'entité (si j'ai bien compris). Donc je suis dans le faux? (ce sont des concepts avec lesquels je dois encore m'habituer (et lire tout ce que vous avez dit)).
    La question est plutôt de savoir ce qu’est une caméra : si elle a une sémantique d’entité, ce n’est pas ce qu’il faut faire (dans ce cas, elle ne devrait pas être copiable, donc tu n’as de toute manière pas le choix). Si elle a une sémantique de valeur, c’est tout à fait acceptable et d’ailleurs la seule solution (si elle a une sémantique de valeur, elle n’a pas de fonction pour la modifier).

    Dans ton cas, je serais tenté de dire qu’une caméra a une sémantique d’entité, et donc, je ne procèderai pas comme toi. Par contre, la caméra ne devrait à mon avis pas être possédée par le renderer : de mon point de vue, la caméra est un paramètre du renderer au moment du rendu, mais ce n’est pas à lui de la modifier, sa durée de vie est indépendante de celle du renderer.

  13. #13
    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
    La caméra devrait être dépendante de la scène qui la contient.
    La dite scène est "rendu" au final par le renderer. En passant la scène au renderer, il a toutes les informations pour afficher(en précisant quelle caméra de la scène utiliser).

  14. #14
    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
    A mon avis, ce qui viole Demeter, c'est de considérer que le render à la responsabilité de créer la caméra mais pas de la manipuler. D'où la nécessité d'utiliser des getter.

    Il me semble préférable de considérer que la caméra est un objet créé et manipulé par l'utilisateur (au même titre que les objets 3D, les lumières, etc.) et qu'il la passe en paramètre au render. On aurait alors :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Render r;
    Camera c;
    c.setPosition(x, y);
    r.setCamera(r); // ou addCamera
    Dans ce cas, Demeter est respecté.

    Citation Envoyé par Flob90 Voir le message
    (***) Je ne considère ici que les classes métiers (ie celle qui interviennent dans l'architecture même) et pas les différentes classes à visées plus technique (typiquement les pointeurs intelligents).
    Sauf erreur de ma part, ce type de classe (comme les POD ou les conteneurs) sont des exceptions à Démeter

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

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par bretus Voir le message
    Qu'implique l'accès publique à un membre (le mal absolu)?
    Je ne suis déjà pas d'accord pour nommer ça le mal absolu
    Citation Envoyé par bretus Voir le message
    Si on donne l'accès publique à un membre "x" sur une classe "Point", on se prive de tout refactoring vers une autre représentation interne.
    [snip exemple]
    Autant dire que ça n'est pas très souple
    C'est possible, mais est-ce qu'on a vraiment besoin de cette souplesse ? Surtout si elle a un coût ?
    Déjà, il existe des classes qui ne sont que des aggrégations de données, sans vraiment un comportement associé (sauf la notion d'une certaine cohérence à la construction). Pour de telles classes, je n'hésite pas à mettre tous mes membres en public (j'écris d'ailleurs souvent une telle classe 'struct'). Ce qui est très rare dans mon code est d'avoir un mélange d'accès différents pour différentes données membres d'une même classe.

    L'exemple académique du point en (x,y) que l'on pourrait vouloir basculer en (arg,mod) me semble un peu artificiel (même si je l'utilise dans mes cours, il est simple à comprendre et expliquer). Pourquoi ? Parce que l'interface d'une classe, ce ne sont pas seulement les prototypes de ses fonctions publiques et de ses fonctions virtuelles, mais c'est aussi un tas de choses, dont les performances.

    Si appeler une fonction getX passe de rien du tout à deux calculs de trigonométrie, les utilisateur verront que le code a changé, même s'il conserve la même interface. Je ne pense pas qu'une bibliothèque puisse faire ce genre de modifications sans l'accord de ses clients, qui vont alors devoir eux aussi modifier du code. On n'est pas vraiment dans la pure théorie du découplage entre code.

    Un autre coût, plus sournois (mais là, de nombreuses personnes sont en désaccord avec moi), c'est que le C++ ne fourni pas d'outils pour rendre l'utilisation de fonctions aussi agréable que l'utilisation de données membre. Je préfère largement dire
    result.R = (data.R + data.G + data.B) / 3;que result.setR((data.R() + data.G() + data.B())/3);.


    Toutes ces parenthèses, nuisent à la lisibilité, et sont source de bugs et de perte de temps.

    Certains vont me répondre que la bonne solution est d'avoir du code result = unAlgorithmeIntelligent(data). Dans certains cas, je suis d'accord. C'est plus réutilisable, documentée et tout. Mais il y a des domaines où les combinatoires des données membre existent à l'infini, et ne sont quasiment pas répétées. Et ou finalement fournir les centaines d'algorithmes spécifiques à chaque fois, on n'améliore pas la lisibilité, et on repousse juste le problème d'un cran.
    Citation Envoyé par bretus Voir le message
    Qu'implique l'accès en référence const et non const à un membre (intermédiaire)
    [snip]
    On peut :
    - modifier la représentation interne (passer _x,_y en _coordinate)
    Pas vraiment, même si un wrapper peut permettre de faire semblant dans certains cas, au prix d'une certaine lourdeur
    Citation Envoyé par bretus Voir le message
    On ne peut pas :
    - mettre par la suite une logique lors de la modification (par exemple, pré-calculer la norme lors de setX)
    On peux, toujours avec un wrapper, toujours aussi lourd
    Citation Envoyé par bretus Voir le message
    - contrôler la cohérence interne de la représentation (A prohiber sur un interval min,max par exemple)
    Idem
    Citation Envoyé par bretus Voir le message
    Qu'implique l'accès en getter constant (readonly) et setter
    [snip]
    On peut :
    - changer la représentation interne
    Voir mes remarques du point 1
    Citation Envoyé par bretus Voir le message
    En guise d'exemple, dans le cas d'un système de rendu, on pourrait introduire la notion de "monde" fournissant l'accès aux différents éléments du système de rendu. Chaque élément du système de rendu à accès à World (sans l'exposer). Tous les éléments du système sont accessibles en descendant les relations à partir de World.
    Je n'aime pas trop cette notion de god object...
    Citation Envoyé par bretus Voir le message
    Qu'est-ce que l'on perd en possibilité de refactoring : Pas grand chose voir rien :
    - Si on déporte la caméra sur un Viewer, il suffira de transformer l'accès à la camera dans la classe World
    - Si on met en place un système multi-caméra, il suffira de renvoyer la caméra active dans getCamera.
    Là, tu supposes qu'il n'y a qu'une caméra active. On peut envisager au moins une caméra par renderer, voir plusieurs (dans la scène affichée, on affiche un écran qui lui même affiche la scène selon un autre angle, voir par exemple le jeu Portal qui joue à fond sur ce principe)
    Citation Envoyé par bretus Voir le message

    En somme, plutôt que de s'obstiner à priver l'utilisateur du chaînage, ne vaut-il pas mieux le guider dans un chaînage intelligent partant d'un point d'accès central (ci-avant World) en fournissant des relations qui aient un sens?

    Que pensez vous de cette approche?
    En l'occurrence, je préfère à priori la solution proposée plus tard qui propose de passer la caméra en argument du renderer.
    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.

  16. #16
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Je suis plutôt d'accord avec vous. Ma caméra a une sémantique d'entité, ne devrait pas être copiable (quitte à mettre les constructeur de copie et autre en private?) et que j'ai tout fait de travers.
    Je n'ai rien à dire pour ma défense, il est vrai. à l'heure actuelle, même si je viole des tas de principes (et de personnes semble t-il ) mon programme fonctionne.
    Ce qui me chagrine, c'est que je dois donc faire une classe Scene (ou similaire) qui elle, aura le contrôle de la durée de vie de la Camera. Le Renderer, comme vous dites, doit prendre en paramètre la camera lors du dessin.
    (Faut que je refasse tout mon code )

    Merci pour vos indications
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  17. #17
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Bonsoir,

    Citation Envoyé par JolyLoic Voir le message
    Je ne suis déjà pas d'accord pour nommer ça le mal absolu
    C'est possible, mais est-ce qu'on a vraiment besoin de cette souplesse ? Surtout si elle a un coût ?
    Excès de prudence peut-être.

    Citation Envoyé par JolyLoic Voir le message
    L'exemple académique du point en (x,y) que l'on pourrait vouloir basculer en (arg,mod) me semble un peu artificiel (même si je l'utilise dans mes cours, il est simple à comprendre et expliquer). Pourquoi ? Parce que l'interface d'une classe, ce ne sont pas seulement les prototypes de ses fonctions publiques et de ses fonctions virtuelles, mais c'est aussi un tas de choses, dont les performances.
    Juste remarque.

    Citation Envoyé par JolyLoic Voir le message
    Un autre coût, plus sournois (mais là, de nombreuses personnes sont en désaccord avec moi), c'est que le C++ ne fourni pas d'outils pour rendre l'utilisation de fonctions aussi agréable que l'utilisation de données membre. Je préfère largement dire
    result.R = (data.R + data.G + data.B) / 3;que result.setR((data.R() + data.G() + data.B())/3);.
    Si tu parles des notions de property ou des getter/setter "magique", je pense que leur présence rendrait moins parano en matière de possibilité de refactoring.
    En leurs absences, le passage de public à get/set génère des changements cassants.

    Citation Envoyé par JolyLoic Voir le message
    [...]Je n'aime pas trop cette notion de god object...Là, tu supposes qu'il n'y a qu'une caméra active. On peut envisager au moins une caméra par renderer, voir plusieurs (dans la scène affichée, on affiche un écran qui lui même affiche la scène selon un autre angle, voir par exemple le jeu Portal qui joue à fond sur ce principe)
    En l'occurrence, je préfère à priori la solution proposée plus tard qui propose de passer la caméra en argument du renderer.
    Ca se vaut je pense, sauf que tu préfères un couplage faible entre le renderer et ce qui l'appel... Dans l'approche World, le renderer peut récupérer l'ensemble des caméras actives. Ca oblige l'appelant du renderer à connaitre les besoins du renderer (caméra et autre) mais ça se défend

    A propos du "god-object", sans insister lourdement , LittleWhite ressent toutefois le besoin de Scene pour gérer la durée de la caméra.

    ++,
    merci de vos précisions

  18. #18
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Citation Envoyé par bretus Voir le message
    A propos du "god-object", sans insister lourdement , LittleWhite ressent toutefois le besoin de Scene pour gérer la durée de la caméra.
    Oui, mais ce n'est pas comparable au "god-object" (enfin je crois), d'une part, car un moteur 3D à souvent (si ce n'est pas tout le temps) la notion de scène, qui contient les géométrie, les lumières, les matériaux, les cameras.
    Alors que dans le cas d'un "god-object" dans un moteur 3D, on se retrouverai avec les shaders, les scènes, les textures et tout ce que l'on peut imaginer d'utile.
    Après, le besoin d'une scène et d'une part à cause que je n'en ai pas mais aussi car la caméra ne peut pas être couplé aussi lourdement avec le renderer (cela à peut de sens disons). Donc il faut bien une autre classe

    EDIT:
    Surtout que j'ai oublié de dire, si "god-object" celui ci gérerai la durée de vie de tout les objets. Si destruction de celui-ci, il détruira Scène + Renderer.
    Alors que en fait, une Scene, peut être détruite et que l'on garderai le Renderer (ainsi que les texture / shaders chargés). Donc la scène n'est pas un "god-object" à proprement parler
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  19. #19
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Je suis peut être un peu lourd, mais comme je suis assez nouveau sur les sémantiques de classes, je voudrais savoir quelle était votre méthode pour savoir si votre classe à une sémantique d'entité ou de valeur. (Genre une question magique que l'on peut se poser pour résoudre le doute).

    Car, récemment, j'ai utilisé une classe Map (une carte 2D pour un jeu de tuiles) qui contient deux std::vector, un pour les tuiles, un pour les unités.
    Mon problème, c'est que l'on pourrait chercher à redéfinir l'opérateur == que cela fonctionnerai. (Mais pas les autres opérateurs, comme désigné dans la FAQ).
    Donc j'imagine que cela prendra une sémantique d'entité, mais je ne suis pas sur à 100%

    Et puis, je voulais savoir, si j'ai une classe à sémantique d'entité, que je veux la créer juste pour une fonction (durée de vie d'une fonction) dois-je obligatoirement utilisé un pointeur ou une référence, ou puis-je utiliser un type statique afin que le programme détruise la classe tout seul, sans que je ne m'en préoccupe.

    Finalement, il serait bien d'avoir une sorte de méthode que l'on lirai pour savoir comment construire une classe proprement (genre, une liste de questions qu'ils faut toujours se poser). Car il me semble que ce ne soit pas si simple. Est-ce possible ?
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  20. #20
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je suis peut être un peu lourd, mais comme je suis assez nouveau sur les sémantiques de classes, je voudrais savoir quelle était votre méthode pour savoir si votre classe à une sémantique d'entité ou de valeur. (Genre une question magique que l'on peut se poser pour résoudre le doute).
    Pour moi, elle a une sémantique d’entité dès lors qu’un changement de son état n’en fait pas un objet distinct.

    Par exemple, dans ton cas, déplacer une caméra n’en fait pas un objet distinct.

    À l’inverse, l’objet coordonnées que tu utilises pour positionner ta caméra a clairement une sémantique de valeur.

    Car, récemment, j'ai utilisé une classe Map (une carte 2D pour un jeu de tuiles) qui contient deux std::vector, un pour les tuiles, un pour les unités.
    Mon problème, c'est que l'on pourrait chercher à redéfinir l'opérateur == que cela fonctionnerai. (Mais pas les autres opérateurs, comme désigné dans la FAQ).
    Donc j'imagine que cela prendra une sémantique d'entité, mais je ne suis pas sur à 100%
    J’ai envie de dire que oui. D’autant que modifier les unités sur ta map n’en fait clairement pas une map distincte.

    Et puis, je voulais savoir, si j'ai une classe à sémantique d'entité, que je veux la créer juste pour une fonction (durée de vie d'une fonction) dois-je obligatoirement utilisé un pointeur ou une référence, ou puis-je utiliser un type statique afin que le programme détruise la classe tout seul, sans que je ne m'en préoccupe.
    Tu peux laisser le compilateur gérer sa durée de vie, si elle se limite au corps d’une fonction. Ce que tu n’as pas le droit de faire, c’est de la copier (≠ cloner). Ça relève du détail d’implémentation là où la distinction entité/valeur relève de la conception (et peut potentiellement être remise en question lors de l’implémentation pour des raisons de perf -> objets à sémantique de valeur, mais modifiables quand même pour éviter les trop nombreuses copies).

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Pointeur et héritage...
    Par Zenol dans le forum C++
    Réponses: 2
    Dernier message: 08/03/2006, 12h31
  2. Passge par référence & héritage
    Par jsatla dans le forum C++
    Réponses: 11
    Dernier message: 04/01/2006, 17h44
  3. [VB.NET]Besoin de précision pour architecture 3-tiers
    Par Dnx dans le forum Windows Forms
    Réponses: 8
    Dernier message: 14/09/2005, 09h09
  4. Besoin de précision sur TThread
    Par psau dans le forum C++Builder
    Réponses: 2
    Dernier message: 15/02/2005, 23h35
  5. Réponses: 8
    Dernier message: 26/08/2004, 18h59

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