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 :

Spécialisation d'un type de retour d'une fonction, par template ?


Sujet :

Langage C++

  1. #1
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut Spécialisation d'un type de retour d'une fonction, par template ?
    Bonjour,

    je me remets au C++ après une bonne dizaine d'années, et je découvre doucement l'utilisation massive des templates et les nouveautés de c++11.

    J'ai une petite question pratique:

    - j'ai un scengraph, composé d'instances de Node qui elles-même peuvent contenir une liste de Nodes enfants. Et une fonction getChild() pour accéder à ses enfants via un index.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Node {
      public:
        void appendChild(Node* child);
        Node* getChild(int index);
        void setPosition(int x, int y);
      private:
        std::vector<Node*> children;
    };
    - différentes sous-classes de Node: Rectangle, Cercle, Texte, avec leurs fonctions propres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Rectangle : public Node {
      public:
        void setLargeur(int l);
        void setLongueur(int L);
      private:
        int x,y;
    }
    class Cercle : public Node {
      public:
        void setRayon(int r)
      private:
        int rayon;
    }
    Le problème: quand je récupère un enfant d'un noeud, je reçois un Node*, donc je ne peux pas appeler directement une fonction spéciale de tel ou tel sous-type de Node (genre setRayon, setLargeur, ...).
    Il m'est donc impossible de faire quelque chose du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Node * parent = new Node();
    parent->addChild(new Cercle());
    /* ... */
    parent->getChild(0)->setRayon();
    ... ou encore...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Rectangle* myRect = parent->getChild(0);
    ... sans devoir faire un cast statique explicite, genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (Rectangle*)(parent->getChild(0))->setRayon(123);
    J'ai la sensation que c'est quelque chose qui pourrait éventuellement être résolu en utilisant une sorte de 'struct wrapper' template qui proposerait des operateurs de casting pour tous mes sous-types de node. Mais je n'ai aucun idée de sa réalisation concrète (ni même si c'est possible)

    Une idée ?

    Merci d'avance.
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 186
    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 186
    Points : 17 126
    Points
    17 126
    Par défaut
    un Node* n'est pas forcément un Rect* ou un Circle*.
    Si tu veux un Rect*:
    Sois tu le mémorises aussi dans une seconde liste (ou simplement un pointeur, s'il est seul), parce qu'il a un importance plus grande qu'être simplement un node.
    Sois tu utilises une fonction plus générale et virtuelle de Node, comme un update(), que tu redéfinis pour la classe Rect


    Pour comparaison, la SFML, que je commence à manipuler, utilise une classe Transformable définissant des propriétés, position, scale et rotation.
    Toute classe héritant de Transformable est uniformément modifiable. C'est ainsi le cas de Shape, CircleShape, Sprite etc
    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

  3. #3
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    D'abord, merci pour ta réponse.

    Ces solutions ne me conviennent pas ; ce que je voudrais (*) c'est de la sugar syntax, quitte à payer le prix le risque d'un dynamic_cast qui hurle en runtime.

    Il y a également la possibilité d'avoir une fonction membre template dans Node pour retourner le type dudit template, mais on en revient à devoir préciser ce qu'on veut exactement comme type dans notre accès au Node:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        parent->getChild<Cercle>(0)->setRayon(123);
    Mais sinon je pensais à quelque chose comme une classe proxy qui proposerait tout un tas d'opérateur de cast implicite, qui se construit avec un pointeur de Node et qui peut caster ça en pointeur de Rectangle, Cercle, ...



    (*) enfin j'en ai pas vraiment besoin, c'est plus pour savoir et comprendre si techniquement c'est quelque chose de faisable, et si oui comment
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 113
    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 113
    Points : 32 958
    Points
    32 958
    Billets dans le blog
    4
    Par défaut
    Ben à part du dynamic_cast tu n'auras absolument aucun moyen d'appeler une méthode de Circle sur un Node. Et vu que Rect et Circle n'ont strictement rien à voir..
    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
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Ben à part du dynamic_cast tu n'auras absolument aucun moyen d'appeler une méthode de Circle sur un Node. Et vu que Rect et Circle n'ont strictement rien à voir..
    Je pense aussi, mais ma question portait plus sur le fait de savoir s'il y avait un moyen ou pas d'encapsuler ce casting dans quelque chose qui permettrait que ça se fasse automatiquement, sans avoir à le spécifier explicitement dans le code à chaque fois qu'on veut accéder à un Node.

    L'idée globale était:

    - de remplacer "Node* getChild(int index)" par quelque chose de la forme "NodePtrWrapper getChild(int index)"
    - que cette struct NodePtrWrapper propose autant d'opérateurs de conversion implicite) de type que les sous classes disponibles (Rectangle, Cercle, ...):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
      class NodePtrWrapper {
        public:
          NodePtrWrapper(Node* node) : nodePtr(node) {}
          operator Rectangle*() const { return(dynamic_cast<Rectangle*>(nodePtr); }
          operator Cercle*() const { return(dynamic_cast<Cercle*>(nodePtr); }
        private:
          Node* nodePtr;
    }
    Ainsi, on aurait quelque chose du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Rectangle* rect = parent->getChild(27);
    ... avec:
    - getChild qui retourne le NodePtrWrapper
    - NodePtrWrapper qui propose une conversion implicite de lui même vers un Rectangle*
    - rect qui reçoit un Rectangle*


    et/ou


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    parent->getChild(21)->setRayon(123);
    ... avec:
    - getChild qui retourne le NodePtrWrapper
    - NodePtrWrapper qui propose une conversion implicite de lui-même vers un Cercle*
    - setRayon(123) qui est appelé sur un Cercle*
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Salut,
    Citation Envoyé par nouknouk Voir le message
    Je pense aussi, mais ma question portait plus sur le fait de savoir s'il y avait un moyen ou pas d'encapsuler ce casting dans quelque chose qui permettrait que ça se fasse automatiquement, sans avoir à le spécifier explicitement dans le code à chaque fois qu'on veut accéder à un Node.
    Ouaip, en gros, cela s'appelle le double dispatch.

    Il y a meme un DP qui l'utilise massivement (bien qu'il présente quelques limites, entre autres lorsque le nombre de types tend à augmenter). J'ai nommé : le DP visiteur !

    Car, de manière générale, si tu as été "assez bête" pour perdre le type réel d'un de tes objets et que tu en es arrivé à ne le connaitre que sous la forme d'un (pointeur sur) objet du type de base, la seule solution viable et évolutive va passer par le polymorphisme et le double dispatch
    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

Discussions similaires

  1. Réponses: 2
    Dernier message: 09/12/2010, 21h52
  2. Type de retour d'une fonction PL/PGSQL
    Par the java lover dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 21/01/2009, 12h13
  3. [PL/SQL] type de retour d'une fonction
    Par foffffa dans le forum SQL
    Réponses: 4
    Dernier message: 27/03/2008, 16h06
  4. Réponses: 5
    Dernier message: 29/09/2006, 18h17
  5. [Oracle 9.1] Types de retour d'une fonction PL/SQL
    Par ftrifiro dans le forum PL/SQL
    Réponses: 8
    Dernier message: 12/10/2005, 17h54

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