IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Gros soucis de compréhension du polymorphisme


Sujet :

Langage C++

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2010
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2010
    Messages : 33
    Par défaut Gros soucis de compréhension du polymorphisme
    Bonjour,

    La question que je vais poser ici est basique, mais le fait est que je n'arrive pas à y trouver de réponse. Je n'arrive pas à saisir comment utiliser le correctement polymorphisme.

    Je prends un exemple très simple pour illustrer mon problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Transformable
    {
    protected :
       float   pos_x;
       float   pos_y;
       float   rotation;
    };
     
    class Player : public Transformable
    {
    public :
       void   set_name( const std::string& name );
    protected :
       std::string   name;
    };
     
    class Building : public Transformable
    {
    public :
       void   open_door( void );
    protected :
       bool   is_door_open;
    };
    Imaginons que je veuille faire un jeu, qui contiendrait de nombreux objets différents ayant tous leurs propres spécificités ainsi que certains points en commun (des joueurs, des arbres, des armes...). Si je les stocke par polymorphisme sur un pointeur, comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::list< Transformable* >   object_list;
     
    object_list.push_back( new ( Player ) );
    object_list.push_back( new ( Player ) );
    Tous mes objets sont stockés dans la même liste, mais je perds l'accès aux méthodes des classes filles de Transformable. Je sais bien qu'il est possible d'employer des virtuelles pures pour surplanter des méthodes de la classe mère, mais imaginons que mes classes filles possèdent certaines méthodes qui leur sont propres. Il y a possibilité de downcaster, mais j'ai lu que c'était à éviter car crado. Pour contourner le problème, je pourrais stocker mes objets par catégorie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::list< Player* >     players_list;
    std::list< Building* >   buildings_list;
    Sauf que ça me paraît franchement sale, surtout si il y a beaucoup d'objets différents et que les listes se multiplient.

    Du coup, j'en arrive à ma question : Comment stocker mes objets de la manière la plus générique possible sans pour autant perdre des méthodes au passage? Quelle est la manière idéale de faire cela en C++?

    Merci d'avance.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Sauf que ça me paraît franchement sale, surtout si il y a beaucoup d'objets différents et que les listes se multiplient.
    Tu peux toujours utiliser une map, avec en clé le type de l'objet.

    Sinon, pour ton cas tu as le dynamic_cast, et ca me choque pas plus que ca, seulement tu risques de voir des choses gênantes du style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for iterator in obj_list
    if iterator is typeof player
    else if iterator is typeof building
    ...
    ce qui est peut etre pas l'idéal.

    Rien ne t'empêche de préserver l'héritage, mais un autre conteneur est probablement plus adapté.

  3. #3
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Si tu cherches à mettre des arbres avec des humains, ça va certainement poser problème. Pourquoi ? Simplement parce que ces deux "objets" n'ont pas les mêmes fonctionnalités et traitements.

    Le polymorphisme, c'est pas fait pour ranger des objets dans un même container pcq t'as la flemme de créer des classes en plus. C'est fait pour pouvoir effectuer des traitements qui ont la même fonction, mais qui ne s'effectue pas de la même façon. Par exemple si dans ton jeu, il y a une ferme avec plein d'animaux, alors tu peux faire un héritage pour tous les animaux qui crient, par conséquent tu pourras appeler la méthode "crie()", sur tous les animaux, sans pour autant savoir quel est l'animal qui crie.

    En bref, réfléchis aux objets qui font la même chose, pour que tu puisses factoriser certains traitements.

    D'un autre côté, je vois qui tu fais un héritage sur "Transformable", qui n'a que modérément sa place ici. Dans ce cas, j'aurais plutôt tendance à privilégier la composition, car tu ne peux pas dire qu'un building EST-UNE matrice de transformation. Par contre, tu peux dire qu'un building A-UNE transformation, ce qui d'or et déjà beaucoup plus logique.

    De toutes façons, il faut que tu poses ton clavier, et prenne un crayon pour modéliser ton programme sur PAPIER. Apprend l'UML si tu ne sais pas comment faire.

    Finalement, je finirai pour un petit conseil à part, n'utilise pas des std::list parce que tu dis "des listes d'objets". Utilise des vectors. Je te laisse chercher les raisons sur le forum ou web, on en a déjà assez parlé.

  4. #4
    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 : 51
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Pourquoi vouloir mettre tous ces objets dans une liste ? Une réponse pourrait être : Pour les afficher, il faut bien que le moteur graphique connaisse l'ensemble des objets, quels que soit leur nature.

    Certes. Dans ce cas, le type de base ne serait probablement pas Transformable mais Displayable, ou GraphicalObject, ou que sais-je encore. Et ce qui serait important dans ce cas là serait plus la méthode virtuelle Display.

    Maintenant, certains de ces objets sont des personnage, et possèdent des méthodes spéciales connues de l'IA, par exemple, et que d'autres sont juste des obstacles utilisés par l'algorithme de calcul de chemin. Le plus simple est alors de créer dans ces parties du code des listes(*) du bon type. L'IA aurait une liste de personnages (qui est peut-être une classe de base), et l'algo de calcul une liste d'obstacles, ou encore une matrice de dimension 2 ou 3 avec des obstacles, ou toute autre structure de données qui va bien pour cet algorithme.

    Comment faire le lien avec le fait que personnage, obstacle et graphical object sont trois aspects d'un même objet ? Il y a plusieurs solutions. On peut imaginer par exemple qu'un monstre hérite de GraphicalObject, de Personnage, et éventuellement d'obstacle, selon le style du jeu. Ou on peut imaginer qu'un personnage possède une représentation graphique.

    Dans tous les cas, il va falloir assurer une certaine cohérence entre ces différents aspects. Quand l'IA décide qu'un personnage avance, sa représentation graphique doit changer de position, et le système de calcul de chemin doit vider une case et en remplir une autre, par exemple.



    (*) list est ssouvent égal à std::vector en c++
    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.

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Dans ces cas là, je fais des listes/vecteurs/maps de pointeurs, par catégorie. Et si j'ai besoin de faire des traitements génériques, je rajoute une liste qui contient les pointeurs vers tous les éléments concernés. Peu importe si le pointeur d'un même élément est stocké dans deux structures de données différentes. Ça ne coûte rien, de stocker/chercher un pointeur.

    Quant à savoir comment ajouter les fonctionnalités de Transformable, je préconiserais quant à moi l'héritage privé, avec éventuellement du CRTP.

  6. #6
    Membre Expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Par défaut
    std::set pour stocker les pointeurs est souvent approprié. (std::map selon le cas, mais plus rare).

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par germinolegrand Voir le message
    std::set pour stocker les pointeurs est souvent approprié. (std::map selon le cas, mais plus rare).
    Je me méfie énormément de ces sentences "à l'emporte pièces"...

    Qu'importe ce que l'on met dans les différentes collections, ce qui importe, c'est l'usage que l'on fera des éléments que l'on y aura placés.

    Un set ou une map seront particulièrement efficaces lorsqu'il s'agira de rechercher un élément donné parmis d'autres tout en assurant une unicité au niveau du facteur discriminant.

    Par contre, si l'idée est "simplement" de parcourir un ensemble d'éléments pour y appliquer des vérifications ou modificiations, que tu ne fais que rarement de recherche d'éléments sur ta collection, une liste ou un vecteur peuvent s'avérer beaucoup plus utiles et efficaces.

    Il ne faut en effet pas oublier que l'insertion d'éléments dans un set ou dans une map est particulièrement lente, du fait qu'il faut équilibrer l'arbre binaire sous jascent à chaque insertion
    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

  8. #8
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2010
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2010
    Messages : 33
    Par défaut
    Sinon, pour ton cas tu as le dynamic_cast, et ca me choque pas plus que ca
    Le dynamic cast fonctionne effectivement bien pour ce genre de choses, mais voilà : http://cpp.developpez.com/faq/cpp/?p...RS_downcasting

    Et comme je cherche à coder le plus proprement possible, j'aimerais éviter ce genre de pratiques quand ça n'est pas réellement nécessaire.

    Le polymorphisme, c'est pas fait pour ranger des objets dans un même container pcq t'as la flemme de créer des classes en plus.
    D'accord, c'est exactement ce que j'avais mal compris au sujet du polymorphisme à la base. Je l'ai pratiqué dans l'optique que ça servait surtout à stocker ses classes de manière générique (c'est ce qu'on nous enseigne à Epitech ), ce qui m'a toujours posé des problèmes de conceptions puisque je me refusais à downcaster.

    Pour ce qui est de la classe Transformable, je suis parfaitement d'accord avec toi et c'est ce que je fais déjà, j'utilise la composition. J'ai utilisé l'héritage ici juste pour donner un exemple (certes mauvais) de polymorphisme.

    Quant à savoir comment ajouter les fonctionnalités de Transformable, je préconiserais quant à moi l'héritage privé, avec éventuellement du CRTP.
    J'ai une préférence pour la composition car on m'a apprit à ne jamais abuser de l'héritage, sous peine d'avoir de gros problèmes de conception si le code se complexifie. Ceci dit, j'imagine effectivement que l'héritage fonctionne aussi très bien dans ce cas précis.


    Quant aux conteneurs à utiliser, je vais faire des recherches en me basant sur ce que vous m'avez conseillé afin de trouver ce qui correspondra le mieux à mon cas.

    Merci beaucoup pour toutes vos réponses, elles m'ont beaucoup aidées et vont me permettre de continuer sur de meilleures bases.

  9. #9
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Citation Envoyé par RT222 Voir le message
    Je l'ai pratiqué dans l'optique que ça servait surtout à stocker ses classes de manière générique (c'est ce qu'on nous enseigne à Epitech ),
    Entre ce que le prof a compris et ce qui sort de sa bouche, et du coup ce que les élèves comprennent, il y a parfois un grand pas. Que ce soit à Epitech ou autre part, je pense que rien ne rivalise (en complément du cours) avec le bouquin référence du domaine… Par exemple, pour l'orienté objet, tu as http://conception.developpez.com/liv...bj#L2212122705

    Enfin l'école c'est bien pour t'ouvrir à des trucs que t'irais pas voir tout seul mais je trouve qu'on a rarement le temps d'approfondir.

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par RT222 Voir le message
    J'ai une préférence pour la composition car on m'a apprit à ne jamais abuser de l'héritage, sous peine d'avoir de gros problèmes de conception si le code se complexifie. Ceci dit, j'imagine effectivement que l'héritage fonctionne aussi très bien dans ce cas précis.
    Es-tu sur que ce qu'on t'a appris ne se référait pas à l'héritage public ?
    Et as-tu compris quels étaient les problèmes susceptibles de se présenter avec l'héritage ?

    Avec les politiques, il n'est pas inhabituel de faire de l'héritage privé multiple avec 4 ou 5 parents. Et le gars qui a inventé ce design pattern n'est pas un nain.

  11. #11
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2010
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2010
    Messages : 33
    Par défaut
    http://www.thedotnetfrog.fr/2008/05/...que-lheritage/
    http://blog.emmanueldeloget.com/inde...et-composition

    Ce n'est pas à l'école qu'on m'a appris à privilégier la composition. Et attention, je n'ai jamais dis que j'avais banni l'héritage de mon code, bien au contraire, je m'en sers beaucoup. C'est juste que j'utilise plutôt la composition quand l'héritage ne me paraît pas être le meilleur choix.

    Et puis il me paraît plus logique de dire Objet a une Position plutôt que Objet est une Position. Après, comme précisé en introduction, je suis loin d'être un expert en C++, et je serais ravi que tu me prouve la supériorité de l'héritage dans ce cas précis.

    Entre ce que le prof a compris et ce qui sort de sa bouche, et du coup ce que les élèves comprennent, il y a parfois un grand pas.
    En fait, ils nous introduisent au polymorphisme de cette manière, en nous faisant stocker des classes sur un pointeur d'un type dont elles héritent, sans nous expliquer que ce n'est pas son intérêt final. Et en soutenance, lorsque nos codes sont vérifiés, le fait d'utiliser le polymorphisme pour stocker est au pire encouragé, mais jamais déconseillé. Alors évidemment on prend l'habitude... Je serais le seul à m'être fait avoir, je me remettrait en question au lieu de critiquer l'école. Mais tous les élèves de ma promo commentent la même erreur, je pense donc que c'est bien l'enseignement d'Epitech qui est à blâmer.

    Par exemple, pour l'orienté objet, tu as http://conception.developpez.com/liv...bj#L2212122705
    Il a l'air intéressant en effet, si je dois acheter un bouquin sur la conception ça sera celui là. J'ai déjà le langage C++ de Stroustrup, et je m'y réfère souvent en cas de soucis. Mais il est si compliqué qu'il m'embrouille parfois plus qu'il ne m'aide.

  12. #12
    Membre expérimenté
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 159
    Par défaut
    Citation Envoyé par RT222 Voir le message
    Ce n'est pas à l'école qu'on m'a appris à privilégier la composition. Et attention, je n'ai jamais dis que j'avais banni l'héritage de mon code, bien au contraire, je m'en sers beaucoup. C'est juste que j'utilise plutôt la composition quand l'héritage ne me paraît pas être le meilleur choix.
    Attention, oodini parle d'héritage privé.
    Dans une héritage privé, toutes les attributs hérités deviennent privés dans la classe dérivée.
    Il faut donc écrire une interface publique à la classe pour manipuler ces attributs.
    On est conceptuellement parlant bien plus proche d'une composition que d'un héritage public (ce n'est pas une relation "est-un", pas de polymorphisme d'inclusion avec héritage privé).

    edit: d'ailleurs, arrêtez moi si je me trompe, il me semble que l'héritage privé est un peu spécifique au C++. Dans d'autre langages on utilisera une composition pour dans la même conception.

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Une remarque concernant le dogme "est-un" de l'héritage public : le design pattern Décorateur en s'y conforme pas, et est pourtant très utilisé.

    Quant à la composition, il me semble que si on est dogmatique sur sa sémantique, cela ne conviendrait pas non plus : un Player n'est pas composé d'un Transformable.

  14. #14
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Tous ces sites parlent d'héritage public, alors que comme l'a signalé valAa, je parlais d'héritage privé.

    Citation Envoyé par RT222 Voir le message
    Et puis il me paraît plus logique de dire Objet a une Position plutôt que Objet est une Position. Après, comme précisé en introduction, je suis loin d'être un expert en C++, et je serais ravi que tu me prouve la supériorité de l'héritage dans ce cas précis.
    Dans ton cas précis, la réponse est dans la question : tu avais mis les membres de Transformable en accès protégé, ce qui avait du sens. Si dorénavant tu utilises cette classe via la composition, tu es obligé de mettre ses membres en public, ou de déclarer les classes clientes comme amies.

    Citation Envoyé par RT222 Voir le message
    En fait, ils nous introduisent au polymorphisme de cette manière, en nous faisant stocker des classes sur un pointeur d'un type dont elles héritent, sans nous expliquer que ce n'est pas son intérêt final. Et en soutenance, lorsque nos codes sont vérifiés, le fait d'utiliser le polymorphisme pour stocker est au pire encouragé, mais jamais déconseillé.
    Je ne comprend pas ce que tu veux dire par là.

    Citation Envoyé par RT222 Voir le message
    J'ai déjà le langage C++ de Stroustrup, et je m'y réfère souvent en cas de soucis. Mais il est si compliqué qu'il m'embrouille parfois plus qu'il ne m'aide.
    Ce bouquin de Stroustrup n'est pas des plus pédagogiques...

  15. #15
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2010
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2010
    Messages : 33
    Par défaut
    Mea Culpa.

    Attention, oodini parle d'héritage privé.
    Dans une héritage privé, toutes les attributs hérités deviennent privés dans la classe dérivée.
    Il faut donc écrire une interface publique à la classe pour manipuler ces attributs.
    D'accord, je vois bien de quoi il s'agit. Je viens de trouver un article sur ce sujet :
    http://bruce-eckel.developpez.com/li...sition#L14.7.2

    Il y est dit :
    Ainsi, l'héritage privéest utile si vous voulez dissimuler une partie des fonctionnalités de la classe de base.
    Ce qui n'est pas mon cas. Je prends pour exemple ma classe Point_3d actuelle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    enum Coordinate_system
    {
    	CS_WORLD,
    	CS_LOCAL
    };
     
    class Point_3d
    {
    public :
    			Point_3d(	const Vector& position = Vector( 0.0f, 0.0f, 0.0f ),
    					const Vector& rotation = Vector( 0.0f, 0.0f, 0.0f ),
    					const Vector& scale = Vector( 1.0f, 1.0f, 1.0f ) );
    			Point_3d( const Point_3d& point_3d );
    	Point_3d&	operator=( const Point_3d& point_3d );
    	void		set_position( const Vector& position );
    	void		translate( const Vector& offset );
    	void		advance( const float distance );
    	void		orient_to( const Vector& target_point );
    	void		set_rotation( const Vector& rotation );
    	void		rotate( const Vector& angle );
    	void		set_scale( const Vector& scale );
    	void		scale( const Vector& factor );
    	const Vector&	get_position( void ) const;
    	const Vector&	get_rotation( void ) const;
    	const Vector&	get_scale( void ) const;
    	float		get_distance( const Vector& point ) const;
    	void		coordinate_system( const Coordinate_system coordinate_system );
     
    protected :
    	virtual void	update( const Transform& transform );
     
    private :
    	Vector			m_position;
    	Vector			m_rotation;
    	Vector			m_scale;
    	Transform		m_last_transform;
    	Coordinate_system	m_coordinate_system;
    };
    Il m'est très pratique de pouvoir accéder à chacune de ces méthodes individuellement, je ne pense donc pas avoir intérêt à utiliser l'héritage privé ici, sous peine d'avoir à créer une lourde interface dans la classe qui en hériterait pour le même résultat au final. Mais je comprends bien que dans certains cas il soit intéressant de dissimuler l'implémentation d'une classe contenue dans une autre.

    Quant à la composition, il me semble que si on est dogmatique sur sa sémantique, cela ne conviendrait pas non plus : un Player n'est pas composé d'un Transformable.
    Pour déterminer quand hériter ou composer, je me sers de "est" et "a". Player a des Coordonnées, Fusilier est un Soldat, Soldat a une Arme, Arme est un Objet... Je trouve ça très simple et ça me semble plutôt efficace.

    Dans ton cas précis, la réponse est dans la question : tu avais mis les membres de Transformable en accès protégé, ce qui avait du sens. Si dorénavant tu utilises cette classe via la composition, tu es obligé de mettre ses membres en public, ou de déclarer les classes clientes comme amies.
    Pas forcément! Voilà la manière dont j'utilise ma classe Point_3d par composition :

    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
     
    #include "Point_3d.hpp"
     
    class Player	
    {
    public :
    //des methodes de Player
    Point_3d	coords; //la classe Point_3d est publique, mais ses membres restent private
     
    private :
    //des membres de Player
    };
     
    Player	main_player;
     
    main_player.coords.set_position( Vector( 10.0, 10.0, 0.0 ) );
    main_player.coords.advance( 25.0 );
    ...
    Pour le fait de stocker en utilisant le polymorphisme, je parle du fait de s'en servir dans le but d'avoir un seul et unique pointeur sur lequel stocker toutes ses classes, et de pouvoir les manipuler toujours à partir de ce même pointeur en downcastant.

  16. #16
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Voilà la manière dont j'utilise ma classe Point_3d par composition :
    Je pense que ce n'est pas la bonne façon de le faire, comme souvent avec les membres publiques.

    En mettant ce membre public, tu exposes ce membre à tous les utilisateurs de la classe player. Or ils n'ont pas à connaitre ce détail.

    Dans ce cas précis, je me demande si utiliser un héritage privé avec des using sur les méthodes adéquates ne serait pas plus approprié.

  17. #17
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2010
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2010
    Messages : 33
    Par défaut
    Oui mais je trouve ça lourd, parce que dans le cas où il y a pas mal de méthodes et que toutes me sont utiles, il faut les redéclarer dans la classe fille à l'aide du mot clé using, tandis qu'avec la composition telle que je l'utilise c'est tout bête. C'est pas que ça soit compliqué de copier coller des déclarations de méthodes d'une classe à une autre, mais ça alourdi le code des classes filles et je n'aime pas trop ça.

    Est-ce ce que la différence entre ce que tu me propose (héritage privé + using) et ce que je fais actuellement (composition publique) est autre que syntaxique? Parce que j'ai du mal à saisir ce que j'aurais à gagner à utiliser l'héritage privé ici.

  18. #18
    Membre Expert

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

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

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par RT222 Voir le message
    En fait, ils nous introduisent au polymorphisme de cette manière, en nous faisant stocker des classes sur un pointeur d'un type dont elles héritent, sans nous expliquer que ce n'est pas son intérêt final. Et en soutenance, lorsque nos codes sont vérifiés, le fait d'utiliser le polymorphisme pour stocker est au pire encouragé, mais jamais déconseillé. Alors évidemment on prend l'habitude... Je serais le seul à m'être fait avoir, je me remettrait en question au lieu de critiquer l'école. Mais tous les élèves de ma promo commentent la même erreur, je pense donc que c'est bien l'enseignement d'Epitech qui est à blâmer.
    Deux solutions : soit c'est mal expliqué, soit le prof est à coté de la plaque. Ca peut arriver. J'ai souvenance qu'à L'Epita, du temps où j'y étais, le cours de C++ avait a peut près autant d'intérêt pour un apprenti programmeur que les courses de chameau en ont pour les étudiant en lettre classique (ou, autrement dit, la matière était mal enseignée ; je ne jette pas la pierre au prof - le C++ était encore un langage méconnu, en cours de standardisation, et mis à pars le Stroustrup, il y avait peut de livre vraiment construit sur le sujet).

    Aujourd'hui, le C++ est mieux compris ; on sait ce que l'héritage, la composition, pourquoi il faut utiliser celui-ci ou celui-là, quel est l'intérêt du polymorphisme, etc. Du coup, avoir un cours mal agencé ou non compréhensible est à la limite de la faute professionnelle. Un cours de C++ devrait commencer par une introduction à la conception objet, et donc par expliquer les 5 principes de base (OCP, LSP, ISP, DIP et SRP). A partir de là, on peut mieux expliquer les tenants et les aboutissants de la composition, de l'héritage et de toutes les options qu'offre le langage utilisé (C++ ou autre ; je ne suis pas sectaire).

    Citation Envoyé par RT222 Voir le message
    Il a l'air intéressant en effet, si je dois acheter un bouquin sur la conception ça sera celui là. J'ai déjà le langage C++ de Stroustrup, et je m'y réfère souvent en cas de soucis. Mais il est si compliqué qu'il m'embrouille parfois plus qu'il ne m'aide.
    Ce livre EST intéressant. Tout comme de nombreux autres (par exemple, le "Agile Software Development" de R. C. Martin). Le Stroustrup est de peux d'aide en ce qui concerne la conception objet (même si le livre en parle ici et là, puisqu'il tente de lister les bonnes pratiques de programmation en C++).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

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

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. interface à concevoir toute simple et gros soucis
    Par skystef dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 02/02/2006, 16h31
  2. [Visual Studio 2003] J'ai un très gros souci !
    Par bart64 dans le forum EDI/Outils
    Réponses: 2
    Dernier message: 18/11/2005, 15h01
  3. [C#][Visual C# Express] Gros souci avec Excel
    Par poullos dans le forum EDI/Outils
    Réponses: 7
    Dernier message: 18/11/2005, 13h15
  4. Petit soucis de compréhension
    Par AlexB59 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 26/10/2005, 10h18
  5. Gros soucis avec pgaccess et postgresql
    Par Missvan dans le forum PostgreSQL
    Réponses: 9
    Dernier message: 13/04/2004, 16h16

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