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 :

[Template] Définition d'une classe à l'intérieur d'une classe


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Octobre 2006
    Messages : 74
    Points : 52
    Points
    52
    Par défaut [Template] Définition d'une classe à l'intérieur d'une classe
    Bonjour à tous,

    je suis à la recherche de solution par rapport à un petit problème que j'ai dans un TP....

    en gros, j'ai une classe définit à l'intérieur d'une autre classe (IteratorPrefixe) qui elle même est définit dans un fichier header pour templates... (euh... me suivez vous encore, parce que je suis pas sur d'être très clair :S)

    donc.... voici le header
    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
    62
    63
    64
    65
    66
    67
    68
     
    #ifndef TRIE_HPP
    #define TRIE_HPP
    #include <utility>
    #include <vector>
    #include <string>
    #include <stdexcept>
    using namespace std;
    #define NBLETTRESMAX 26
    #define LETTREMIN 'a'
     
    template <typename T> class Trie {
        friend class IteratorPrefixe;
        public:
            // Cree un trie basé sur un alphabet de nblettres, ou nblettres doit avoir une valeur comprise
            // entre 1 et NBLETTRESMAX inclusivement
            Trie(unsigned nblettres) throw(runtime_error);
            // Ajoute un élément dont la clé est donnée en premier argument et le contenu en second argument
            // Le contenu doit être défini (pointeur différent de NULL)
            // La clé doit être composée de lettres valides (soit les lettres comprises entre a inclusivement et a+nblettres exclusivement
            //      par exemple :   si nblettres vaut 3, a, b et c sont les seuls caractères autorisés;
            //                      si nblettres vaut 15, seules les lettres entre a et o inclusivement sont autorisées.
            // Renvoie true si l'insertion a pu se faire, renvoie false sinon.
            bool ajouteElement(string, T*) throw(runtime_error);
            // Supprime un élément dont la clé est donnée en argument et renvoie le contenu du noeud supprimé
            // La clé doit être composée de lettres valides (voir ci-dessus)
            // Peut egalement supprimer en meme temps des ancetres du noeud mentionne, si ces ancetres sont devenus inutiles
            // Renvoie NULL si l'élément a supprimer n'existe pas
            T* supprimeElement(string cle) throw(runtime_error);
            // Cherche un élément dont la clé est donnée en argument et renvoie le contenu associé
            // La clé doit être composée de lettres valides (voir ci-dessus)
            // Renvoie NULL si la clé n'existe pas
            T* chercheElement(string cle) throw();
            // Classe d'itérateur permettant de parcourir le trie en profondeur en mode préfixe
            class IteratorPrefixe;
            // Renvoie un itérateur pointant sur le premier élément du parcours du trie en profondeur en mode préfixe
            IteratorPrefixe pbegin() throw(runtime_error);
            // Renvoie un itérateur pointant au-delà du dernier élément du parcours du trie en profondeur en mode préfixe
            IteratorPrefixe pend() throw();
        private:
            unsigned nbLettres;
            T* element;
            vector<Trie<T> *> enfants;
            Trie<T> * parent;
            // Cette fonction supprime un noeud et ses ancêtres devenus inutiles. Elle fait essentiellement le meme travail
            // que supprimeElement : c'est la façon de désigner le noeud a supprimer qui change. De plus, contrairement a
            // supprimeElement, elle ne retourne aucune information sur le noeud supprimé.
            void supprime(Trie<T> * noeud) throw();
            // Cette fonction cherche un noeud en fonction d'une clé donnée. Elle fait essentiellement le meme travail
            // que chercheElement mais renvoie une référence au noeud trouvé (ou NULL si le noeud n'existe pas)
            // La clé doit être composée de lettres valides (voir ci-dessus)
            Trie<T>* cherche(string cle) throw(runtime_error);
    };
    template <typename T> class Trie<T>::IteratorPrefixe{
        friend class Trie<T>;
        public:
            IteratorPrefixe() : arbre(NULL), noeudCourant(NULL), cleCourante("") {};
            pair<string, T*> operator*() {return make_pair(cleCourante, noeudCourant -> element);} ;
            IteratorPrefixe operator++()throw(runtime_error);
            void operator=(IteratorPrefixe iter) {arbre = iter.arbre; noeudCourant = iter.noeudCourant; cleCourante = iter.cleCourante;};
            bool operator==(IteratorPrefixe iter) {return arbre == iter.arbre && noeudCourant == iter.noeudCourant;};
            bool operator!=(IteratorPrefixe iter) {return arbre != iter.arbre || noeudCourant != iter.noeudCourant;};
        private:
            Trie<T> * arbre;
            Trie<T> * noeudCourant;
            string cleCourante;
    };
    #endif /* TRIE_HPP */
    et voici le code problématique du cpp associé
    (il faut remarqué que le header est séparé du cpp malgré le fait que ce soit des templates.... spécifications du tp ... )

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
    #include "Trie.hpp"
    #include <iostream>
    #define POSITIONA 97
    static bool checkCle(string cle, int nblettres);
    template<typename T>
    Trie<T>::Trie(unsigned nblettres) throw(runtime_error) {
        if (nblettres > NBLETTRESMAX || nblettres < 1)
            throw runtime_error("Trie() : nombre de lettres hors-bornes!");
        nbLettres = nblettres;
        element = NULL;
    }
     
    template<typename T>
    bool Trie<T>::ajouteElement(string uneCle, T* unElement) throw(runtime_error) {
        int noCle;
        if (unElement == NULL)
            throw runtime_error ("ajouteElement() : Insertion d'élement 'null'");
        if (!checkCle(uneCle, nbLettres))
            throw runtime_error ("ajouteElement() : Cle invalide.");
        noCle = tolower(uneCle[0])-POSITIONA;
        if (uneCle.length() == 0) {
            element = unElement;
            return true;
        } else {
            if (enfants.size() == 0) {
                for (int x=0; x<nbLettres; x++) {
                    enfants.push_back(NULL);
                }
            }
            if (enfants[noCle] == NULL)
                enfants[noCle] = new Trie<T>(nbLettres);
            return enfants[noCle]->ajouteElement(uneCle.substr(1,(uneCle.length()-1)), unElement);
        }
    }
    template<typename T>
    T* Trie<T>::supprimeElement(string uneCle) throw(runtime_error) {
        int noCle;
        T* returnElement;
        if (!checkCle(uneCle, nbLettres))
            throw runtime_error ("supprimeElement() : Cle invalide.");
        noCle = tolower(uneCle[0])-POSITIONA;
        if (chercheElement(uneCle) != NULL) {
            if (uneCle.length() > 0) {
                returnElement = enfants[noCle]->supprimeElement(uneCle.substr(1,(uneCle.length()-1)));
                if (uneCle.length() == 1)
                    enfants[noCle] = NULL;
            }
            else {
                returnElement = element;
                element = NULL;
            }
        } else {
            returnElement = NULL;
        }
        return returnElement;
    }
    template<typename T>
    T* Trie<T>::chercheElement(string uneCle) throw() {
        int noCle;
        noCle = tolower(uneCle[0])-POSITIONA;
        if (enfants.size() > 0 && uneCle.size() > 0)
            if (enfants[noCle] != NULL)
                return enfants[noCle]->chercheElement(uneCle.substr(1,(uneCle.length()-1)));
            else
                return NULL;
        else
            if (enfants.size() == 0 && uneCle.size() > 0)
                return NULL;
            else
                return element;
    }
     
    IteratorPrefixe pbegin() throw(runtime_error)
    {
    }
    le problème dans ce code est à la fin (IteratorPrefixe pbegin()...)
    cela me crée une erreur :
    error: 'IteratorPrefixe' does not name a type

    Donc, c'est là que je suis bloqué

    Merci d'avance
    FadeOut

  2. #2
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Bonjour,

    1/ N'oublie pas que quand tu définis les fonctions membres & co dans un .cpp, tu n'es plus dans la classe, donc il faut préfixer les types & co par le nom de la classe.

    2/ Je te conseille de lire les Q/R suivantes, de la FAQ C++ :
    http://cpp.developpez.com/faq/cpp/?p...creation_class
    http://cpp.developpez.com/faq/cpp/?p...LATES_typename
    http://cpp.developpez.com/faq/cpp/?p...VERS_templates

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Octobre 2006
    Messages : 74
    Points : 52
    Points
    52
    Par défaut
    Malgré le fait que j'ai lu le FAQ au complet, de haut en bas, de bas en haut, de gauche à droite.... je n'ai malheureusement toujours pas trouvé de solutions...

    j'ai essayé plusieurs trucs dont :

    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
     
    //1
    template <typename T>
    IteratorPrefixe pbegin() throw(runtime_error)
    {
    }
     
    //2
    template <typename T>
    Trie<T>::IteratorPrefixe pbegin() throw(runtime_error)
    {
    }
     
    //3
    template <typename T>
    IteratorPrefixe Trie<T>::pbegin() throw(runtime_error)
    {
    }
     
    //4
    IteratorPrefixe::IteratorPrefixe pbegin() throw(runtime_error)
    {
    }
     
    //5
    IteratorPrefixe IteratorPrefixe::pbegin() throw(runtime_error)
    {
    }
    et toutes me donne une erreur similaire
    error: expected constructor, destructor, or type conversion before...

    Je suis près d'être découragé... mais bon... ce n'est pas ma philosophie... c'est pas un ptit template qui va m'avoir...!!!!

  4. #4
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <typename T>
    typename Trie<T>::IteratorPrefixe Trie<T>::pbegin() throw(runtime_error)
    {
    }

    Pour typname, c'est dit dans l'une des Q/R de la FAQ que je t'ai indiquée.

    Ensuite, n'oublie pas que pbegin et IteratorPrefixe sont déclarés dans (à l'intérieur de) ta classe Trie<T>, donc il faut préfixer toute utilisation de ces derniers qui se situe en dehors de Trie<T> par Trie<T> justement, pour que le compilateur sache où chercher.

    Par contre, fais gaffe, comme dit dans la FAQ, tu ne peux pas compiler une fonction ou classe template séparément de sa déclaration.
    Tu peux les séparer en deux fichiers, à condition que tu inclues le fichier où tu les définis à la fin de celui où tu les déclares.
    Cf http://cpp.developpez.com/faq/cpp/?p...VERS_templates

    Tu comprends tout cela ? Besoin d'autres explications ?

  5. #5
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Au fait, les deux fois où apparaît "friend" -> superflu !
    Déjà, IteratorPrefixe a accès aux données de Trie<T> en tant que "nested class" (classe à l'intérieur d'une autre). Pour l'inverse, hmm... Ca peut éventuellement servir mais je ne suis pas très friand de "friend", car ça montre souvent un problème dans la conception ou une mauvaise compréhension des choses.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Octobre 2006
    Messages : 74
    Points : 52
    Points
    52
    Par défaut
    Merci encore pour les réponses,

    malheureusement, je suis pris avec le fichier header car il m'est imposé

    nous avons contournés le problème du header de cette façon...

    dans le fichier Trie.cpp nous avons au tout début
    #include "Trie.hpp"

    et dans le fichier main.cpp au lieu d'inclure "Trie.hpp" nous incluons "Trie.cpp"


    je sais que cela ne constitue pas une pratique courrante... mais tel sont mes directives pour ce TP....

    En passant Alp, très beau chapeau Un joyeux temps des fêtes à toi!

  7. #7
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par FadeOut Voir le message
    Merci encore pour les réponses,

    malheureusement, je suis pris avec le fichier header car il m'est imposé

    nous avons contournés le problème du header de cette façon...

    dans le fichier Trie.cpp nous avons au tout début
    #include "Trie.hpp"

    et dans le fichier main.cpp au lieu d'inclure "Trie.hpp" nous incluons "Trie.cpp"


    je sais que cela ne constitue pas une pratique courrante... mais tel sont mes directives pour ce TP....
    Et ça compile ?
    La "bonne pratique" c'est un fichier .h/.hpp avec les déclarations, et un fichier .tpp (par exemple) avec les définitions, qui est inclu à la fin du .h/.hpp.

    Enfin entre les bonnes pratiques et ce qu'enseignent une grande partie des profs...

    Citation Envoyé par FadeOut Voir le message
    En passant Alp, très beau chapeau Un joyeux temps des fêtes à toi!
    Merci

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 10/10/2013, 11h11
  2. Classe à l'intérieur d'une méthode
    Par logiciel_const dans le forum Débuter avec Java
    Réponses: 5
    Dernier message: 29/12/2010, 12h35
  3. Classe à l'intérieur d'une classe ?
    Par hsoussou dans le forum Débuter
    Réponses: 12
    Dernier message: 14/01/2009, 13h23
  4. Instance de classe à l'intérieur d'une autre
    Par cobolfingaz dans le forum C#
    Réponses: 12
    Dernier message: 17/01/2008, 11h25
  5. Réponses: 5
    Dernier message: 15/05/2007, 20h51

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