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 :

Encapsuler ou dériver ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre actif
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Par défaut Encapsuler ou dériver ?
    Bonjour à tous,

    Au fil de mes pérégrinations programmatiques, j'ai plusieurs fois fait l'expérience d'un dilemme. Lorsque je veux créer classe en contenant une autre ainsi que d'autres données, je ne sais jamais quand ajouter ladite classe en attribut ou au contraire, quand hériter de ladite classe.
    Exemple : Admettons que je programme en 2D et que j'ai une classe Sprite qui contient l'imagine affichée ainsi que la position dudit Sprite dans le monde. Je veux créer une classe Personnage : un personnage est représenté par un sprite, mais contient d'autres informations : nom, vie, etc... ainsi qu'une flopée de méthodes qui vont avec.
    Convient-il d'avoir le Sprite en attribut, ou plutot d'hériter du Sprite ?
    Instincitvement j'utilise la solution de l'attribut, mais lorsque ledit attribut possède beaucoup de méthodes, le code s'alourdit beaucoup (Si par exemple, pour mon personnage, je dois créer une méthode afficher qui appelle la méthode afficher du Sprite). D'un autre côté, hériter de Sprite me laisse perplexe, notamment parceque le Personnage "contient" un Sprite plus qu'il n'en est un. Niveau LSP et tout ça, ça me semble bof.

    Du coup, en règle générale, comment choisir la technique utilisée ?

  2. #2
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut
    Une première question que tu dois te pauser est : doit-on pouvoir utiliser un personnage comme on utilise un sprite ? Mais attention, si la réponse est "oui", il faut continuer l'investigation : ce besoin est-il réel et justifié ou est-ce un gimmick, une mauvaise conception ? C'est une idée d'entrée en matière.

  3. #3
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    De manière générale, si la classe de base n'a aucune fonction virtuelle, y'a peu de chance que tu doives en hériter.
    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.

  4. #4
    Membre actif
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Par défaut
    Merci pour les réponses. Dans mon cas tout incite à encapsuler, mais je vais devoir copier quelques méthodes du Sprite pour qu'elles s'appliquent au Personnage. (En fait, mon "souci déclencheur" tenait dans le fait que je déplace mon personnage et non son sprite, qui est toujours au point 0,0 des coordonnées... du personnage. Parfait pour déplacer l'image, moins pour calculer les collisions avec les méthodes du Sprite.)
    D'un autre côté, je ne vois dans mon cas aucun inconvénient à hériter de Sprite, notamment car Personne comme Sprite héritent des meme classes abstraites d'interfaces Drawable et Transformable. Du coup, dans ce cas particulier, le Personnage est "parallèle" au Sprite qu'il contient... Ca porte à confusion

  5. #5
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par bisthebis Voir le message
    Parfait pour déplacer l'image, moins pour calculer les collisions avec les méthodes du Sprite.)
    D'un autre côté, je ne vois dans mon cas aucun inconvénient à hériter de Sprite, notamment car Personne comme Sprite héritent des meme classes abstraites d'interfaces Drawable et Transformable. Du coup, dans ce cas particulier, le Personnage est "parallèle" au Sprite qu'il contient... Ca porte à confusion
    A priori, Sprite et Collision c'est deux choses différentes, donc 2 classes, ça devrait pas être regroupé.

    Un Personnage n'à imo pas à être Drawable.

    Tu peux tout à fait exposer le Sprite pour l'affichage.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Personnage : public Transformable {
    public:
       Sprite const& sprite() const() { return m_sprite; }
     
    private:
       Sprite m_sprite;
    };
     
    // ...
    Personnage p;
    draw(p.sprite());
    Si le fait d'exposer le Sprite dérange, tu peux l'exposer via une classe utilitaire.
    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
    template <class T>
    struct DrawT : public Drawable {
       void draw(RenderTarget& rt) const {
          rt.draw(m_sprite);
       }
     
       DrawT(T const& obj): m_sprite(obj.sprite()) { };
     
    private:
       Sprite m_sprite;
    };
     
    class Personnage : public Transformable {
    public:
       DrawT<Personnage> drawer() const { return DrawT<Personnage>(*this); }
     
    private:
       friend class DrawT<Personnage>;
       Sprite const& sprite() const { return m_sprite; }
     
       Sprite m_sprite;
    };
     
    Personnage p;
    auto d = p.drawer();
     
    draw(d));

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Normalement, ton personnage est positionné par des coordonnées propres aux données (en metres, par exemple), et le sprite en pixels.
    Tu as probablement du écrire une fonction, quelque part dans le code graphique, qui converti ces coordonnées de jeu en coordonnées écran.

    C'est cette fonction qui te donnera les coordonnées du sprite

    Ca ne devient évident qu'en 3D, où les coordonnées du monde sont relatives à un repère stable et 3D, tandis que les coordonnées en pixels sont liées à la projection caméra.

  7. #7
    Membre actif
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Par défaut
    Un Personnage n'à imo pas à être Drawable.

    Tu peux tout à fait exposer le Sprite pour l'affichage.
    En fait, Drawable ne possède qu'une métode virtuelle pure, draw. Mon implémentation de draw dans personnages appelle simplement la fonction draw du Sprite contenu. J'imagine que c'est fort équivalent à un accesseur du Sprite si ledit accesseur n'a pas d'autre utilité.

    Normalement, ton personnage est positionné par des coordonnées propres aux données (en metres, par exemple), et le sprite en pixels.
    Tu as probablement du écrire une fonction, quelque part dans le code graphique, qui converti ces coordonnées de jeu en coordonnées écran.

    C'est cette fonction qui te donnera les coordonnées du sprite
    Pour l'instant j'utilise comme unité de mesure le "pixel en zoom nul", mais réflexion faite je pense pertinent de changer ça. Je pense que je vais placher là-dessus

  8. #8
    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 : 50
    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
    Citation Envoyé par bisthebis Voir le message
    Du coup, en règle générale, comment choisir la technique utilisée ?
    La règle en général est le principe de substitution de Liskov (LSP, Liskov Substitution principle, nommé d'après Barbara Liskov). Pour que B dérive de A, il faut que partout où on peut utiliser un A, on puisse substituer un B et que le code soit justifié, logique et cohérent.

    On a souvent tendance à sur-utiliser l'héritage qui est la relation la plus forte qui soit entre deux classes. Du coup, si tu hésites, c'est probablement qu'il vaut mieux t'abstenir
    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.

  9. #9
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Si tu as 2-3 heures à perdre, il y a un livre gratuit sur le développement de jeu à l’ancienne: O'Reilly Media - iPhone Game Development.

    Bon c'est de l'Objective-C, mais c'est facile à comprendre [les premiers chapitres t'expliquent la programmation iOS 3-4-5]: le pdf et les codes sources

    Édit: Le chapitre 5 c'est pour un jeu 3D [très] [très] léger et le chapitre 3 ce sont les fondations. Donc c'est le chapitre 4 qu'il faut regarder

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    De manière générale, tu dois te dire que l'héritage est la relation la plus forte qui puisse exister entre deux classes. C'est donc la relation que l'on essayera d'utiliser le moins possible.

    Si tu te pose la question de savoir s'il est préférable d'utiliser l'héritage ou la composition(/l'agrégation), on peut donc assez facilement partir du principe que la composition (ou l'agrégation) sera sans doute le meilleur choix par défaut.

    En effet, pour que tu puisse faire hériter une classe B d'une classe A, il faut que le principe de substitution de Liskov soit impérativement respecté, ainsi que l'a déjà fait savoir Loic et, pour qu'il soit respecté, il faut que tu puisse envisager d'utiliser ta classe B partout où un objet de type A aurait été attendu.

    Mais ce n'est pas tout : Si tu y réfléchis bien, absolument tout ce qui fera partie de ton jeu sera -- tot ou tard -- destiné à devoir être affiché. De là à estimer que tout ce qui fait partie de ton jeu devrait hériter d'une classe quelconque (de Sprite, par exemple), il n'y aurait qu'un pas, que tu aurais très largement tord de franchir.

    Car, si tu franchis ce pas, tu ne vas pas tarder à te retrouver avec une hiérarchie de classes monstrueuse et totalement ingérable, dans laquelle tout dérive de Sprite.

    Or, même si ton personnage, tes armes, tes potions, tes sors ou que sais-je d'autre finiront bel et bien par devoir être affichés, ce que tu attends de la part de ces différents types d'objets est et restera d'être en mesure de rendre certains services spécifiques, propres à la nature même du type en question.

    De plus, il existe un concept appelé MCV (pour Model Controler View) qui nous incite à essayer de séparer le plus possible la notion d'affichage (que l'on retrouve pour n'importe quel Sprite) du reste du code.

    De ce fait, on se fout pas mal de savoir que ton Personnage est représenté par un Sprite particulier, car, ce que l'on attend en priorité de sa part, c'est qu'il soit capable de fournir des services tels que:
    • répondre à la question "quelle est ta position"
    • répondre à la question "es-tu en vie"
    • obéir à l'ordre "déplace toi vers telle position" ou "déplace-toi de telle distance en X et telle distance en Y"
    • obéir à l'ordre "attaque tel ou tel élément"
    • obéir à l'ordre "équipes-toi de telle ou telle arme"
    • obéir à l'ordre "bois telle ou telle potion"
    • j'en passe, et sans doute de meilleures...

    Et l'idée est donc d'avoir "quelque chose" qui pourra indiquer que, pour représenter ton personnage, il faut utiliser tel sprite particulier, et le faire afficher à telle position particulière. Tu devras, pour faire simple, trouver le moyen de créer une relation "la plus légère possible" entre ton personnage et le sprite qui permet de le représenter, de manière à pouvoir demander l'affichage de ce sprite, sans avoir à s'inquiéter des autres caractéristiques de ton personnage
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre actif
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2015
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2015
    Messages : 26
    Par défaut
    Merci foetus pour le lien, je regarderai ça en détail quand j'aurai du temps


    A la réflexion, faire tout hériter de Sprite semble en effet hasardeux, en revanche je suis instinctivement tenté de tout faire dériver de Drawable pour que chaque objet soit affichable, mais quand on pense en architecture genre MVC (j'ai lu pas mal de trucs là-dessus, mais je n'ai jamais appliqué et ma compréhension n'est que théorique) j'imagine que pouvoir faire monPersonnage.afficher() est mal. Reste que j'ai du mal à comprendre le pourquoi exact
    Est-ce une histoire de "ne remplir qu'une fonction par classe" ?

    Du coup, quelles sont les possibilités propres pour séparer ça ? Avoir le sprite en attribut ? En pointeur ? Autre chose ?
    Je vais devoir relire tout ce que je sais sur le MVC car c'est fort confus pour moi. Faut-il pour chaque objet avoir un objet vue correspondant ? Ou est-ce que la vue correspond à mon moteur graphique ? C'est assez abstrait pour moi

  12. #12
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    A moins d'avoir une classe de manager d'affichage sur lequel enregistrer chacun de tes sprites à leur création, tu ne pourras de toutes façons pas échapper à avoir un équivalent de myPerso.Draw()
    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.

Discussions similaires

  1. Réponses: 31
    Dernier message: 30/03/2006, 16h57
  2. URGENT DRIVER ODBC
    Par Casp dans le forum Débuter
    Réponses: 3
    Dernier message: 28/04/2003, 16h24
  3. [PostgreSQL] PB de drivers JAVA
    Par koundelitch dans le forum Administration
    Réponses: 5
    Dernier message: 14/03/2003, 15h09
  4. [MFC] Utilisation Drivers
    Par LAPLACE dans le forum MFC
    Réponses: 4
    Dernier message: 21/12/2002, 10h29
  5. [MFC](encapsulation ADO) ou placer le code
    Par philippe V dans le forum MFC
    Réponses: 2
    Dernier message: 13/06/2002, 14h58

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