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 :

Problème de conception.


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut Problème de conception.
    Salut,

    je possède une classe de base abstraite (BoundingVolume) dont dérive plusieurs classes. (BoundingBox, BoundingSphere, etc...)

    Je possède également une classe Entity et elle possède un pointeur sur un objet de type BoundingVolume.

    Le problème c'est que je n'arrive pas à trouver comment faire une méthode intersects générique, je voudrais que la méthode intersects sache quel type de BoundingVolume est ce et qu'elle fasse un cast vers l'object de la sous classe avant d'appeler la méthode intersects correspondante pour la sous classe, j'ai donc fait ceci :

    Code cpp : 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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    #ifndef ODFAEG_BOUNDING_VOLUME_HPP
    #define ODFAEG_BOUNDING_VOLUME_HPP
    class TransformMatrix;
    /**
      *\namespace odfaeg
      * the namespace of the Opensource Development Framework Adapted for Every Games.
      */
    namespace odfaeg {
    /**
      * \file boundingVolume.h
      * \class BoudingVolume
      * \brief Manage a bounding volume for collision detection
      * \author Duroisin.L
      * \version 1.0
      * \date 1/02/2014
      *
      * Base class of all bouding volumes of the framework used for collision detection.
      *
      */
    class BoundingBox;
    template <typename D>
    class BoundingVolume {
     
    public :
        /** \fn bool intersects (BoundingAreas &other)
        * \brief this method can be redefined in the sub class to test if two bounding volumes
        * are in collision. (if the method isn't redefined it always return false.
        * We cannot made this methode abstract because, we need to overload the intersects method in subclasses
        * for each volumes types.
        * \param the other bounding volume to test with.
        * \return return true if the two bounding volumes are in collision.
        */
        bool intersects(BoundingVolume *other) {
            //std::cout<<"intersects"<<std::endl;
            std::cout<<static_cast<D*>(other)<<std::endl;
            return intersects(*static_cast<D*>(other));
        }
        virtual bool intersects (BoundingBox &other) {
            return false;
        }
        virtual Vec3f getPosition() {
            return Vec3f(0, 0, 0);
        }
        virtual Vec3f getSize() {
            return Vec3f(0, 0, 0);
        }
        virtual Vec3f getCenter() {
            return Vec3f(0, 0, 0);
        }
        virtual void move (Vec3f t) {
        }
    protected :
        /** \fn BoundingVolume ()
        *   \brief constructor : we cannot create bounding volumes directly, we need to use one of its sub classes.
        */
        BoundingVolume() {}
    };
    }
    #endif // BOUNDING_AREAS

    D correspond au type de la sous classe. (BoundingBox, BoundingSphere, etc...)
    Je fais donc un cast sur le paramètre de la fonction et je rappelle la méthode intersects en lui envoyant le bon type pour le paramètre.

    Le problème est que le cast ne marche pas et me renvoie un pointeur null :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    entity->getCollisionVolume()->intersects(entity2->getCollisionVolume())

    La classe Entity possède un object de type BoundingVolume<BoundingBox>.

    Du coup ça crash dans la méthode intersects de ma classe BoundingBox, donc voilà je cherche une solution à mon problème car là je ne vois pas de trop comment faire ça.

    Ensuite je voudrais former une hiérarchie de tel sorte que la classe BoundingVolume contienne des volumes enfants de n'importe quel type et appeler la méthode intersects récursivement mais je vois pas trop bien comment faire cela en c++.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bon, apparemment ceci règle le problème :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    bool intersects(BoundingVolume *other) {
            if(static_cast<D*>(other))
                return intersects(*static_cast<D*>(other));
            return false;
    }

  3. #3
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Bonsoir,

    ce que tu cherches s'apelle "double dispatch".
    Dans ton cas, tu pourrais aussi avoir une méthode template spécialisée.

    Un static_cast ici, j'y verrais plutôt un dynamic_cast du coup.
    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
    Invité
    Invité(e)
    Par défaut
    Ok, merci!

    Il est vrai que je pourrai faire une méthode template spécialisée aussi, mais comme les méthodes template ne peuvent pas être virtuelle ça n'ira pas dans mon cas.

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    690
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2005
    Messages : 690
    Points : 1 647
    Points
    1 647
    Par défaut
    Tu devrait regarder du coté des méthodes virtuelle...

  6. #6
    Invité
    Invité(e)
    Par défaut
    Sinon j'avais pensé à convertir des std::string en code source à la compilation mais ça ne semble pas être possible : (On peut convertir du code source en std::string mais pas l'inverse)

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::string type = other->children[i]->getType();
    intersects(static_cast<BoundingVolume<INSERT(type)>*>(other->children[i]));

    Ca me met une erreur de compilation (the value of type is not usable in a const expression.

    Ainsi pas besoin de "pattern visitor." et si je veux rajouter un type de volume englobant qui n'existe pas encore et bah je ne dois pas changer le code source de la classe BoundingVolume.

    Par contre il y aurait moyen mais avec un interpréteur c++, mais je n'en ai jamais utilisé, quelqu'un en connaîtrai t'il pas un bon ?

    Ca m'éviterait de devoir changer de language.

  7. #7
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Points : 1 475
    Points
    1 475
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Sinon j'avais pensé à convertir des std::string en code source à la compilation mais ça ne semble pas être possible :
    Le compilateur aura du mal à connaître le type effectif de ce que référencent tes pointeurs BoundingVolume*...donc c'est bien du double dispatch qu'il te faut, comme disait Bousk.
    L'algorithme à appliquer dépend des deux objets, non d'un seul...

  8. #8
    Invité
    Invité(e)
    Par défaut
    Salut, j'ai essayer de faire une classe pour que le compilateur connaisse le type de mes objets mais ça ne semble pas marcher. :/

    Code cpp : 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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    #ifndef TUPLE
    #define TUPLE
    #include <map>
    #include <vector>
    #include <iostream>
    #include <typeinfo>
    namespace odfaeg {
    namespace helper {
    template <int...> struct seq {};
    template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {
     
    };
    template<int ...S> struct gens<0, S...>{
        typedef seq<S...> type;
    };
    }
    template <typename B>
    class DynamicTupleBaseElement {
      public :
          DynamicTupleBaseElement() {
     
          }
          virtual B get() const {
              std::cout<<"get base element"<<std::endl;
          }
    };
    template<typename E, typename B>
    class DynamicTupleElement : public DynamicTupleBaseElement<B> {
        public :
        DynamicTupleElement(E element) {
            std::cout<<typeid(element).name()<<std::endl;
            this->element = element;
        }
        E get() const {
            std::cout<<"get derived element"<<std::endl;
           return element;
        }
        E element;
    };
    template <typename B>
    class DynamicTuple {
        private :
        typename std::map<std::string, DynamicTupleBaseElement<B>*>::iterator f (std::string type) {
            return elements.find(type);
        }
        std::map<std::string, DynamicTupleBaseElement<B>*> elements;
        public :
        template <typename E>
        void addElement (std::string type, E element) {
            DynamicTupleBaseElement<B>* base_element = new DynamicTupleElement<E, B>(element);
            elements[type] = base_element;
        }
        template <typename E>
        bool exists (E element) {
            typename std::map<std::string, DynamicTupleBaseElement<B>*>::iterator it;
            for (it = elements.begin(); it != elements.end(); it++) {
                if (std::is_same<decltype(it->second->get()), E>::value)
                    return true;
            }
            return false;
        }
        template <typename E>
        std::string getType(E element) {
            typename std::map<std::string, DynamicTupleBaseElement<B>*>::iterator it;
            for (it = elements.begin(); it != elements.end(); it++) {
                if (std::is_same<decltype(it->second->get()), E>::value)
                    return it->first;
            }
        }
        auto get(std::string type) -> decltype(this->f(type)->second->get()) {
            std::cout<<typeid(decltype(this->f(type)->second->get()))
            .name()<<std::endl;
            return elements[type]->get();
        }
    };
    }
    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     odfaeg::Serializable s;
        odfaeg::DynamicTuple<odfaeg::Serializable*> dt;
        Base b("A base object");
        dt.addElement("Base", &b);
     
        std::cout<<typeid(dt.get("Base")).name()<<std::endl;

    Par exemple ici j'ai un objet de type Serializable et non pas un objet de type Base, je vois pas comment je pourrais utiliser un double dispatch et puis double dispatch signifie cast non ? donc je dois connaitre le type de l'objet.

    Bref je vois pas trop comment faire ça avec un double dispatch.

  9. #9
    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 Lolilolight Voir le message
    double dispatch signifie cast non ? donc je dois connaitre le type de l'objet.
    Au contraire, le double dispatch permet de se passer d’un cast. Par exemple :

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
     
     
    #include <iostream>
     
    struct Base1;
    struct D1Base1;
    struct D2Base1;
    struct Base2;
     
    struct Base1 {
    	virtual void f(Base2* b)=0;
    };
     
    struct Base2 {
      void g(Base1& b) { b.f(this); }
      virtual void g(D1Base1& b)=0;
      virtual void g(D2Base1& b)=0;
    };
     
    struct D1Base1 : public Base1 {
    	void f(Base2* b) override { b->g(*this); }
    };
     
    struct D2Base1 : public Base1 {
    	void f(Base2* b) override { b->g(*this); }
    };
     
     
    struct D1Base2 : public Base2 {
      void g(D1Base1& b) override { std::cout << "D1Base2::g(D1Base1)\n"; }
      void g(D2Base1& b) override { std::cout << "D1Base2::g(D2Base1)\n"; }
    };
     
    struct D2Base2 : public Base2 {
      void g(D1Base1& b) override { std::cout << "D2Base2::g(D1Base2)\n"; }
      void g(D2Base1& b) override { std::cout << "D2Base2::g(D2Base2)\n"; }
    };
     
    int main()
    {
    	Base1* b1 = new D1Base1();
        Base1* b2 = new D2Base1();
        Base2* b3 = new D1Base2();
    	Base2* b4 = new D2Base2();
     
    	b3->g(*b1);
    	b3->g(*b2);
    	b4->g(*b1);
    	b4->g(*b2);
    	return 0;
    }

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

Discussions similaires

  1. Méthode Finalize et problème de conception
    Par phryos dans le forum Langage
    Réponses: 4
    Dernier message: 19/04/2006, 11h04
  2. [VB6][UserControl et OCX]Problème de conception
    Par jacma dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 19/01/2006, 22h37
  3. Petit problème de conception sur access
    Par coooookinette dans le forum Modélisation
    Réponses: 3
    Dernier message: 18/12/2005, 18h24
  4. Gestion des départements problème de conception
    Par snoopy69 dans le forum Modélisation
    Réponses: 7
    Dernier message: 11/10/2005, 13h08
  5. Problème de conceptions de tables
    Par dtavan dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 23/05/2004, 23h13

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