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 :

Cast d'un std::vector<T> -> std::vector<X>


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club

    Inscrit en
    Avril 2012
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Avril 2012
    Messages : 16
    Points : 39
    Points
    39
    Par défaut Cast d'un std::vector<T> -> std::vector<X>
    Bonjour,

    Je suis confronté à un petit soucis avec le langage C++, je viens donc demander votre aide après avoir pas mal cherché sur le net :/.

    Je travaille sur un moteur de jeu dans lequel j'ai une classe abstraite de base :

    -> Drawable
    Elle contient un tableau de Vertex, un Vertex étant un sommet contenant une couleur et une position.

    Je travaille sur un moteur de particule, j'ai ma classe Emitter héritant de Drawable. Ma classe Emitter utilise des "Particle", il s'agit d'une classe héritant de Vertex, elle ajoute la vitesse de la particule ainsi que sa durée de vie.

    Résumé 1 :
    Drawable <- Emitter
    Vertex <- Particle

    Je souhaite donc tout bêtement stocker dans mon tableau de Vertex mes Particle, jusque là aucun soucis puisque Particle hérite de Vertex.

    Le soucis apparait au moment où je souhaite transmettre mes particules aux "Modifier" (des classes permettant d'ajouter des effets aux particules). En effet, je dois transmettre mon tableau de vertex (std::vector<Vertex> vers std::vector<Particle>).

    Pour résumer :
    Je souhaite caster mon std::vector<Vertex> vers un std::vector<Particle> avant de l'envoyer aux modifiers, sachant que Particle hérite de Vertex.

    Actuellement j'ai tenté plusieurs choses :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<Particle*> particles = std::vector<Particle*>(vertices.begin(), vertices.end());
    Résultat :
    Cannot initialize a parameter of type 'std::vector<Particle> *' with an rvalue of type 'std::vector<Vertex> *'
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    template <class F, class T> 
    struct caster {
    	T operator () (F n) { return (T)n; }
    };
     
    template <class F, class T>
    void convert (const vector<F> &is, vector<T> *os) {
    	insert_iterator<vector<T> > osins(*os, os->begin());
    	transform(is.begin(), is.end(), osins, caster<F,T>());
    }
     
    // Puis :
    convert<Vertex, Particle>(vertices, &particles);
    Résultat :
    No matching conversion for C-style cast from 'sx::Vertex' to 'sx:: Particle'

    Voilà, le résumé de la situation, merci à celui/celle qui trouvera la force de m'aider. Merci d'avance.
    Dono

  2. #2
    Nouveau membre du Club
    Inscrit en
    Août 2003
    Messages
    17
    Détails du profil
    Informations forums :
    Inscription : Août 2003
    Messages : 17
    Points : 30
    Points
    30
    Par défaut
    Pourquoi faire compliqué quand on peut faire simple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    std::vector<Particle*> particles;
    std::vector<Vertex*>::const_iterator it = vertices.begin();
    std::vector<Vertex*>::const_iterator end = vertices.end();
    for(; it != end; ++it)
    {
        particles.push_back(static_cast<Particle*>(*it));
    }
    Par contre static_cast ne fait pas de test de validité, donc si tu n'es pas sur que ton vector est vraiment de type Particle utilise plutot dynamic_cast.

    Mais bon la vrai question est pourquoi a tu besoin de faire un upcast de ton vector. Logiquement si le design est bon tu ne devrais pas avoir a le faire. Soit tu te débrouille pour que tes "modifier" puissent bosser avec ton vector de Vertex, soit tu t'arrange pour que ton emitter garde le vector de Particle sous la main sans le downcasté.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut,

    Le gros problème auquel tu seras confronté dans ton design actuel, c'est que, a prior, les classes (héritant de) drawable peuvent contenir des vertexes qui ne sont pas des particles

    Je vois donc dés à présent un certain nombre de questions à se poser:
    1. Emitter doit il réellement hériter de Drawable (dans le respect de LSP), ou ne fait-il qu'utiliser des fonctionnalités de celui-ci (*)
    2. Particle doit il réellement hériter de Vertex (dans le respect de LSP), ou ne fait elle qu'utiliser des fonctionnalités de celui-ci (*)
    3. Si LSP est respecté en (2), et que tes modifiers ne doivent modifier que des particules, ne pourrais tu pas envisager de transmettre un tableau de (pointeurs sur) vertexes, mais de faire en sorte que tes visiteurs fassent le tri entre les "autres vertexes" (sur lesquels ils n'auraient aucune action ) tes les "particles" (sur lesquelles ils auraient une action)

    Pour ce qui est de (3), tu pourrais parfaitement avoir quelque chose comme
    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
    class Vertex
    {
        public:
            virtual void accept(Modifier & )
            {
                // par défaut, ne fait rien
            }
    };
    class Particle : public Vertex
    {
         virtual void accept(Modifier & m)
         {
            m.visit(*this);
         }
    };
    class Modifier
    {
        public:
            void visitAll()
            {
                for_each(tab.begin(), tab.end(),[](Vertex* v) ) // C++1 inside :D
                    v->accept(*this);
            }
            virtual void visit(Particle & )
            {
                // par défaut ne fait rien
            }
        private:
            std::vector<Vertex*> tab;
    };
    class SpecializedModifier : public Modifier
    {
        public:
            virtual void visit(Particle & p )
            {
                // modification de p selon les besoins
            }
    };
    (*)On ne le répétera en effet jamais assez, mais l'héritage est la relation la plus forte qui puisse exister entre deux types donnés, ce qui fait que c'est aussi la relation qui doit être considérée avec le plus de prudence!!!!

    Elle ne doit être considérée que lorsque l'on peut décemment dire qu'un objet du type dérivé EST-UN objet du type de base au sens du respect du principe de substitution de Liskov.

    En cela, deux types différents peuvent parfaitement présenter la même interface publque (par exemple, la fonction draw() ), mais ne pas présenter de relation d'héritage publique de l'un envers l'autre car on ne peut pas décemment estimer qu'un objet du type dérivé EST-UN objet du type de base

    A défaut de plus d'informations, je dirais que:
    • Emiter utilise sans doute un élément de type Drawable, mais que ce n'en est pas forcément un: son role (si le nom est correctement choisi ) est... d'émettre certains événement en transmettant des informations, sans doute (mais pas forcément ) de type Drawable
    • Une particule n'est pas, d'avantage, un vertex... Le vertex est la "composante traçable" de ta particule, dont tu peux, effectivement, modifier la position depuis ta particule, mais, a priori, je dirais que ta particule a un ensemble de responsabilité qui dépasse largement celles du vertex...
    L'héritage permet de spécialiser les responsabilités, mais est rarement un bon choix quand il s'agit d'en rajouter, voire, de passer à une granularité de responsabilité moins fine

    A moins, bien sur, que tu ne parte dans des héritages génériques basés sur le CRTP, mais tu n'as, à ce moment là, plus réellement de classe de base car Base<T1> est différent de Base<T2>, et l'héritage consiste essentiellement à assurer la cohérence de l'interface du type dérivé

  4. #4
    Nouveau membre du Club

    Inscrit en
    Avril 2012
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Avril 2012
    Messages : 16
    Points : 39
    Points
    39
    Par défaut
    Merci beaucoup à vous pour vos réponses.

    En effet, je remet en doute l'architecture de mon moteur, je réalise que Emitter n'a rien d'un "Drawable", seul les particules sont finalement "dessinable" à l'écran. L'héritage n'a donc rien à faire ici.

    Du coup, je vais devoir réfléchir à comment je vais organiser tout cela, sachant que le reste est plus un problème relatif à OpenGL. (En gros le fait dessiner des GL_Points VS des GL_Quads ou encore le fait de gérer les particules dans un seul VBO)

    En tout cas, merci encore pour vos réponses rapides et très précises, on ne trouve pas ça sur tout les forums.

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

Discussions similaires

  1. std::vector semble ne pas utiliser std::move, pourquoi ?
    Par n0-sheep dans le forum SL & STL
    Réponses: 7
    Dernier message: 15/03/2014, 01h25
  2. Réponses: 4
    Dernier message: 04/06/2012, 15h19
  3. Réponses: 3
    Dernier message: 03/02/2011, 18h09
  4. Réponses: 2
    Dernier message: 25/05/2009, 10h07
  5. Cast sur un std::vector
    Par albat0r dans le forum SL & STL
    Réponses: 3
    Dernier message: 17/06/2007, 23h07

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