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 :

Petite question à propos de l'héritage et des templates.


Sujet :

Langage C++

  1. #1
    Invité
    Invité(e)
    Par défaut Petite question à propos de l'héritage et des templates.
    Salut,

    je voudrais savoir si il est possible de récupérer le type d'un objet dérivé à partir de la classe de base en c++ afin de l'insérer dans un template.

    J'ai une classe BoundingVolumeBase qui me sert juste à stocker un tas de volumes englobants de type différents :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    class BoundingVolumeBase {
    }

    Ma classe BoundingVolume est template, donc, et je veux pouvoir stocker des volumes enfants de n'importe quel type, je fais donc hériter cette classe de BouningVolumeBase et j'utilise type erasure :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template <typename D>
    class BoundingVolume : public BoundingVolumeBase {
    private :
        std::vector<BoundingVolumeBase*> children;
        typedef D& type;
    };

    Pour caster les objets de type BoundingVolumeBase en BoundingVolume<D> j'ai besoin de connaitre le type de D à la compilation, je suis donc obligé de faire ceci :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class BoundingVolumeBase {
             virtual std::string getType() = 0;
    }

    Et de redéfinir cette méthode dans ma classe BoundingVolume et dans toutes les classes héritant de boundingvolume, ainsi je peux connaitre le type et faire un downcast à l'aide d'un if :

    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
     
    template<typename C>
    bool intersects(BoundingVolume<C> other) {
           if (children.size() == 0 && other->children.size() == 0) {
                  return intersects(*static_cast<C*>(other));
           } else if (children.size() == 0 && other->children.size() != 0) {
                  for (unsigned int i = 0; i < other->children.size(); i++) {  
                        if (other->chirldren[i]->getType() == "BoundingBox") {
                             if (intersects(static_cast<BoundingVolume<BoundingBox>*>(other->children[i])))
                                 return true;
                        }   
                  }
           }      
    }

    Mais ceci me parait assez lourd à faire surtout si j'ai beaucoup de classes qui héritent de BoundingVolume, j'aimerais savoir si en c++11 il n'y a pas moyen de récupérer le type de la sous classe à partir de la classe de base et faire un truc comme ceci :

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

    Voilà merci.

  2. #2
    Membre habitué
    Homme Profil pro
    Doctorant en Astrophysique
    Inscrit en
    Mars 2009
    Messages
    312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Astrophysique
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2009
    Messages : 312
    Points : 176
    Points
    176
    Par défaut
    Du CRTP ça passerait à tout hasard ? (http://en.wikipedia.org/wiki/Curious...mplate_pattern)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template <class Derived>
    class BoundingVolumeBase {
    }
     
    template <typename D>
    class BoundingVolume : public BoundingVolumeBase<BoundingVolume<D>> {
    private :
        std::vector<BoundingVolumeBase<BoundingVolume<D>>*> children;
        typedef D& type;
    };
    Ou bien simplement passer D, à la classe de base ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename D>
    class BoundingVolumeBase {
    }
     
    template <typename D>
    class BoundingVolume : public BoundingVolumeBase<D> {
    private :
        std::vector<BoundingVolumeBase<D>*> children;
        typedef D& type;
    };

  3. #3
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Regarde le double disptach et le pattern visitor (boost.visitor ?).

    Rien de simple à l'horizon, j'en est bien peur.

  4. #4
    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 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Le plus simple dans ce cas-là, mais franchement je recommenderais pas trop.
    Tu fais un enum, qui liste tous les types.

    Tu as une méthode virtuelle qui retourne l'entrée d'enum correspondante.


    Mais ça indique le plus souvent juste un mauvais design que de devoir recourir à ça. Ou une méconnaissance du C++ et de l'objet en général.
    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.

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    La suggestion de templater la classe de base est intéressant, car tu n'as probablement pas de raison valable de grouper des BoundingVolume de D différentes.

    Tu peux aussi avoir une classe intermédiaire:
    • BoundingVolumeBase, qui propose des méthodes virtuelles (pures?) comme centre() et contient(x, y, z).
    • BoundingVolume<T> : public BoundingBase, qui permet d'accéder à son contenu de type T
    • BoundingSphere<T> : public BoundingVolume<T>, qui gère une sphère de collision.



    Cela dit, les calculs mathématiques d'intersections sont différentes de selon les deux volumes à considérer.
    La théorie est :
    soit V1(x,y,z) la fonction déterminatrice du premier volume, valant 0 si le point (x,y,z) est hors du volume, 1 sinon.
    soit V2(x,y,z) la déterminatrice du second volume.
    les volumes sont en intersection si et seulement si l'intégrale de V1*v2 dx dy dz est non nulle.

    En pratique, on fait autrement:
    • pour deux sphères, on calcule la distance entre les centres, qui doit être plus grandes que la somme des rayons
    • pour deux cubes alignés sur les axes (AABB: Axis Aligned Bounding Box), on calcule les projections sur les trois axes de cette distance, et on vérifie qu'elles sont plus grandes que les "rayons" dans ces directions.
    • pour des ellipsoïdes, c'est un peu pareil
    • avec des cylindres verticaux, on compare les hauteurs et altitudes, puis la distance en négligeant la verticale (x2-x1)²+(y2-y1)² < (r1+r2)²

    Si les volumes sont convexes, on approxime par l'une de ces formules.
    Si certains sont concaves, on pleure, ou on découpe par morceaux.

    On peut aussi prendre plusieurs volumes de détection, par exemple un cube externe et un sphère interne.

    L'idée des volumes englobants (AABB et sphères) c'est de permettre des calculs rapides, soit en séparant les trois axes, soit en supprimant la notion de direction.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Invité
    Invité(e)
    Par défaut
    Ok, je vais essayer ça.

    Le fait que je ne passe pas le template à la classe de base est parce que je veux avoir un seul type de base pour pouvoir stocker tout mes différents type de volume dans une seule et même collection afin de former une hiérarchie de volumes englobants, ainsi par exemple je peux mettre une AABB autour du corps, une Ellipsoïd autour du bras, etc...
    Le problème avec le template c'est que il peut être de tout type.

    Mon idée de départ était donc de combiner le pattern CRTP et le type erasure. (Principe de boost any)

    J'utilise en effet plusieurs techniques différentes pour détecter l'intersection suivant le type du volume. (Ca dépend de la complexité du volume)

    Il est vrai que je pourrai aussi utiliser boost::variant et les visitors, ça m'éviterais de devoir faire une enum. (ou ce genre de chose)

    Ok bah j'essayerai ça si ce n'est pas trop compliqué à implémenté.

  7. #7
    Membre régulier
    Homme Profil pro
    Ingénieur
    Inscrit en
    Octobre 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Transports

    Informations forums :
    Inscription : Octobre 2006
    Messages : 48
    Points : 97
    Points
    97
    Par défaut
    La solution à base de "getType" est une mauvaise idée.
    Ici, l'héritage ne nous aide pas vraiment et dans une certaine mesure ne se prête pas au problème car le C++ supporte uniquement le single dispatch.

    Pour ""émuler"" un double dispatch (ce dont on a besoin), en C++ il faut utiliser le pattern Visiteur. Ici, je dirai qu'on a le choix :
    - créer des arborescences de classe Visiteurs/Visitées ce qui permet également de créer une collection hétérogène de classe Visitée
    - utiliser boost::apply_visitor et créer une collection hétérogène (au choix grâce à un héritage ou par type erasure non intrusif)

  8. #8
    Invité
    Invité(e)
    Par défaut
    Ok voilà qui répond à mon problème mais je veux pas dépendre de boost, donc, je pense que je vais soit garder cette solution ou bien implémenter moi même le pattern visiteur, bref, faut que je me renseigne de ce côté là.

  9. #9
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    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 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Tu ne veux pas en dépendre? récupère le fichier correspond, et colle le dans tes propres includes. C'est permis par sa licence.

    Sachant que boost est pour l'essentiel header-only.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  10. #10
    Invité
    Invité(e)
    Par défaut
    Ok!

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

Discussions similaires

  1. Petite question à propos des RichTextBox.
    Par Jeano81 dans le forum VB.NET
    Réponses: 26
    Dernier message: 16/03/2015, 17h03
  2. [Javamail] Petite question à propos des Flags
    Par Hellnino18 dans le forum API standards et tierces
    Réponses: 1
    Dernier message: 26/05/2009, 08h49
  3. Petite question à propos du redbook...
    Par Michaël dans le forum OpenGL
    Réponses: 3
    Dernier message: 04/11/2004, 12h54
  4. Petite question à propos d'une requete
    Par ViBy dans le forum Langage SQL
    Réponses: 4
    Dernier message: 15/09/2004, 12h21

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