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 :

Foncteur, classes templates et héritage


Sujet :

C++

  1. #1
    Membre éclairé
    Avatar de Floréal
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 456
    Par défaut Foncteur, classes templates et héritage
    Bonjour,
    Je suis entrain de décelopper une calculatrice en langage interpreté (qui permetra plus tard de génerer, pour cela je fonctionne avec une arboressance de noeuds.
    Ceux ci peuvent être:
    • Des nombres simples, ou une formule de dés (1d6, 2d4): ce sont les feuilles de mon arbre).
    • Des Opérations (je me limites aux opérations basiques: +, -, * et /).

    Pour les opérations, j'ai décidé, plutot que d'implémenter quattres classes filles), d'utiliser la généricité avec les diférents foncteurs de la stl.

    Voici la classe mère abstraite (noeud de base), décrite dans le fichier aDiceNode.h:
    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #ifndef NODE_H
    #define NODE_H
    #include <string>
    #include "../Exceptions/Exceptions.h"
    #include "aDiceNode.h"
    namespace DiceEngine
    {
      namespace Calcul
      {
        /**
         * Classe abstraite de laquelle d&eacute;rivent vous
         * les types de noeuds. Elle permet d'effectuer les
         * calculs demand&eacutes, par la classe
         * <code>cDiceCalculator</code>.
         */
        class aDiceNode
        {
        public:
          /**
           * Simple constructeur d&eacute;finissant une expression.
           * @param expression une expression à calculer.
           */
          aDiceNode(const std::string& expression = "");
     
          aDiceNode(const aDiceNode& source);
     
          /**
           * Destructeur.
           */
          virtual ~aDiceNode();
     
          /**
           * Obtient l'expression à calculer
           * @return une cha&icirc;ne de caractère de l'expression.
           */
          std::string getExpression() const;
     
          /**
           * Effectue le calcul et retourne la valeur obtenue sous
           * forme de cha&icirc;ne.
           * @return Le r&eacute;sultat des opperaion de tous les noeuds
           * effectu&eacute;s de mani&egrave;re r&eacute;curcive.
           */
          std::string execute() throw (Exceptions::eDiceNodeException);
        protected:
          std::string _expression, _name;
          int _value;
     
          /**
           * Dans son impl&eacute;entation, cette fonction doit appeler
           * <code>process()</code>. En cas d'&eacute;chec cas contraire, elle
           * renvoyer une exception. En cas de reussite <code>_value</code>
           * doit &ecirc;tre renseign&eacute;.
           */
          virtual void process() throw(Exceptions::eDiceNodeException) =0;
        private:
        };
     
      }
    }
    #endif // NODE_H
    Voici la classe dérivée décrite et implémentée dans le fichier cDiceOperationNode.inl:

    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
    #ifndef OPERATIONNODE_H
    #define OPERATIONNODE_H
    #include "aDiceNode.h"
    #include <vector>
    #include <string>
     
    namespace DiceEngine
    {
      namespace Calcul
      {
        template <class Operation>
        class cDiceOperationNode : public aDiceNode
        {
        public:
     
          inline cDiceOperationNode(const std::string& expression = "") : aDiceNode::aDiceNode(expression), _children()
          {};
     
          inline cDiceOperationNode(const cDiceCalculator& source) aDiceNode::aDiceNode(source), _children(source._children)
          {};
     
          inline virtual ~cDiceOperationNode()
          {};
     
          inline void addChildren(aDiceNode* node)
          {
            _children.push_back(node)
          };
     
        protected:
          template <class Operation>
          inline void process() throw (Exceptions::eDiceNodeException)
          {
            _value = 0;
            for (std::vector<aDiceNode*>::iterator i = _cildren.begin(); i < _children.end(); i++)
            {
              _value = Operation(_value, *i->_value);
            };
          }
     
          std::vector<aDiceNode*> _children;
        private:
        };
     
      }
     
    }
    #endif // OPERATIONNODE_H
    Lorsque je terste cela, j'obtiens ces erreurs de compilation:
    Compiling: main.cpp
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:19: erreur: expected «;" before «aDiceNode"
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:31: erreur: declaration of «class Operation"
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:11: erreur: shadows template parm «class Operation"
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl: In member function «void DiceEngine::Calcul::cDiceOperationNode<Operation>::addChildren(DiceEngine::Calcul::aDiceNode*)":
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:28: erreur: expected `;' before «}" token
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl: In member function «void DiceEngine::Calcul::cDiceOperationNode<Operation>::process()":
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:35: erreur: «_cildren" was not declared in this scope
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:37: erreur: request for member «_value" in «i->", which is of non-class type «DiceEngine::Calcul::aDiceNode*"
    /home/floreal/dev/DiceCaster/main.cpp: In function «int main()":
    /home/floreal/dev/DiceCaster/main.cpp:34: erreur: cannot declare variable «node" to be of abstract type «DiceEngine::Calcul::cDiceOperationNode<std::plus<int> >"
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:13: note: because the following virtual functions are pure within «DiceEngine::Calcul::cDiceOperationNode<std::plus<int> >":
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/aDiceNode.h:55: note: virtual void DiceEngine::Calcul::aDiceNode::process()
    Process terminated with status 1 (0 minutes, 0 seconds)
    9 errors, 0 warnings
    Voila mon programe principal:
    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
    #include <iostream>
    #include "DiceEngine/DiceEngine.h"
    #include "DiceEngine/Calcul/cDiceOperationNode.inl"
    #include <functional>
     
    using namespace std;
    using namespace DiceEngine::Util;
    using namespace DiceEngine::Exceptions;
    using namespace DiceEngine::Calcul;
     
    int main()
    {
      //Autres tests peu interessants
      cDiceOperationNode<plus<int> > node("53+21");
      return 0;
    }
    Je suppose que j'ai des lacunes concernant la généricité en C++, mais que puis-je faire pour règler ces problèmes?

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Pourquoi process() prend un paramètre template, qui plus ayant le même nom que celui que prend sa classe (cDiceOperationNode) ? En plus si process est template, ce ne sera pas une surdéfinition valide de la fonction virtuelle de la classe mère. A mon avis il ne faut pas lui ajouter de paramètre template.

    En plus tu prends un type en paramètre template, mais tu tentes de l'utiliser comme une instance. Il faut tout d'abord l'instancier.

    Attention aussi aux règles de priorité entre les opérateurs * et ->

    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
    template <class Operation>
    class cDiceOperationNode : public aDiceNode
    {
        protected:
          inline void process() throw (Exceptions::eDiceNodeException)
          {
            _value = 0;
            for (std::vector<aDiceNode*>::iterator i = _cildren.begin(); i < _children.end(); i++)
            {
              _value = _op(_value, (*i)->_value);
            };
          }
     
        private :
          Operation _op;
        };

  3. #3
    Membre éclairé
    Avatar de Floréal
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 456
    Par défaut
    Ah oui en effet ça marche mieu. J'en ai profité pour corriger quelques erreurs dont je ne m'etais pas rendu compte. Je te remercie pour m'avoir apporté ton aide.

    Maintenant je me heure à un autre problème:
    mon compilateur n'aime pas que j'accède à (*i)->_value (j'imagine que c'est bien de là que vient le problème), parce que c'est une proprieté protegée. Ne suis-je pas sencé pouvoir y aceder (sans passer par friend) si aDiceNode est derivée en public?

    -------------- Build: Debug in DiceCaster ---------------
    Compiling: main.cpp
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/aDiceNode.h: In member function «void DiceEngine::Calcul::cDiceOperationNode<T>::process() [with T = std::plus<int>]":
    /home/floreal/dev/DiceCaster/main.cpp:40: instantiated from here
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/aDiceNode.h:47: erreur: «int DiceEngine::Calcul::aDiceNode::_value" is protected
    /home/floreal/dev/DiceCaster/DiceEngine/Calcul/cDiceOperationNode.inl:37: erreur: à l'intérieur du contexte
    Process terminated with status 1 (0 minutes, 0 seconds)
    2 errors, 1 warnings

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

    Informations professionnelles :
    Activité : aucun

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

    Fait déjà attention au fait que (*i)->quelque chose n'aura du sens que dans le cadre ou i est un pointeur de pointeur (ou considérable comme tel)... autrement, c'est (*i).quelque chose qu'il te faudra utiliser.

    D'un autre coté, un membre de classe ayant le marqueur de visibilité protected est accessible depuis les classes qui dérivent de la classe dans laquelle il est déclaré, mais c'est tout...

    C'est à dire que si, de manière générale, tu as des classes sous la forme de
    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
     
    class A
    {
        public:
            A(int i):_i(i){}
            virtual ~A(){}
        protected:
            int _i;
    };
    class B:public A
    {
        public:
            B(int i):A(i){}
            virtual ~B(){}
            void mafonction();
    };
    class C:public B
    {
        public:
            B(int i):B(i){}
            virtual ~C(){}
            void mafonction2();
    };
    tu peux accéder à _i dans les fonctions respectives mafonction et mafonction2, mais tu ne peux pas y accéder dans l'idée d'une fonction externe du genre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int main()
    {
        B b(3);
        C c(5);
        b._i; //erreur... _i n'est pas accessible dans main()
        c._i; //erreur... _i n'est toujours pas accessible dans main()
        return 0;
    };
    Si tu veux pouvoir récupérer _i, il faudra disposer d'une fonction membre de visibilité publique pour ce faire
    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

  5. #5
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    La visibilité protégée est assez vicieuse lorsque tu manipules des classes dérivées. Tu peux jeter un oeil à ce sujet par exemple :
    http://www.developpez.net/forums/sho...0&postcount=17

  6. #6
    Membre éclairé
    Avatar de Floréal
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 456
    Par défaut
    Cela veut-il dire que je suis obligé de declarer la méthode cDiceOperationNode::process() comme friend, dans ma classe abstraite?
    Si c'est le cas, le fait qu'il y ait une généricité m'oblige-t'il a déclarer cette fonction pour chaqu'un des types que j'utilisera (plus<int>, minus<int>, multiple<int> et divide<int>)?

  7. #7
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Encore un truc que je savais pas. Merci Laurent pour ce lien...

  8. #8
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Cela veut-il dire que je suis obligé de declarer la méthode cDiceOperationNode::process() comme friend, dans ma classe abstraite?
    Ce ne serait pas plus simple de faire un accesseur publique en lecture seule sur ta donnée membre _value ?

  9. #9
    Membre éclairé
    Avatar de Floréal
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 456
    Par défaut
    C'est fait, mais je me suis rendu compte que j'avais besoin d'appeller la fonction process() des noeuds enfants, et cette methode est obligatoirement priotégée. Et au final je me rend compte que je suis confronté au même problème. il me semblait qu'en objet ce genre de chose n'arrivait que lorsque la méthode ou la propriété était privée.

Discussions similaires

  1. Foncteur, variadic templates et héritage
    Par coda_blank dans le forum Langage
    Réponses: 8
    Dernier message: 02/10/2011, 22h15
  2. Héritage d'une classe template
    Par zouip dans le forum Langage
    Réponses: 5
    Dernier message: 08/04/2008, 02h29
  3. Héritage de classe template
    Par FunkyTech dans le forum Langage
    Réponses: 2
    Dernier message: 06/02/2008, 19h07
  4. Héritage d'une classe template
    Par Bob.Killer dans le forum Langage
    Réponses: 3
    Dernier message: 14/11/2007, 13h08
  5. Héritage classe template->classe template
    Par zabibof dans le forum Langage
    Réponses: 5
    Dernier message: 11/08/2007, 11h05

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