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 :

Encapsuler une list dans une class


Sujet :

C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut Encapsuler une list dans une class
    Bonjour,

    J'ai une class A:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A
    {
    	public:
    		const std::list<B> &getList() const{return list;}
    		void removeElementFromList(std::list<B>::const_iterator it){/*???*/};
     
    	private:
    		std::list<B> list;
    };
    Grace à la méthode getList(), je peux parcourir la liste private 'list' à l'aide d'un const_iterator.
    Ma question: comment supprimer un élement de cette liste à partir d'un const_iterator à l'aide de la méthode removeElementFromList?

    Biensur, je ne veux pas qu'il soit possible de supprimer un élément de la liste en dehors de ma class 'A'.

    Merci d'avance.

  2. #2
    Membre éprouvé Avatar de nowahn
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 84
    Par défaut
    Bonjour,

    Tu as essayé la fonction list::erase ? Ça devrait marcher.
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void A::removeElementFromList(std::list<B>::const_iterator it)
    {
        list.erase(it);
    }

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut
    Je viens de tester et ça ne fonctionne pas.
    J'ai le droit à cette erreur: 'no matching function for call....'

  4. #4
    Membre expérimenté
    Homme Profil pro
    Consultant BigData
    Inscrit en
    Juillet 2009
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant BigData

    Informations forums :
    Inscription : Juillet 2009
    Messages : 129
    Par défaut
    Il faudrait un peu plus de détails sur l'erreur générée. Quelle fonction n'est pas trouvée ?

    Car la solution proposée par zenux est correcte. Je pense que tu dois avoir fait une petite erreur de frappe quelque part ou alors ça vient d'une autre partie de ton code

  5. #5
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 287
    Par défaut
    Je le verrai bien venir d'un
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    list<B> l = a.getList()
    list<b>::const_iterator w = list.find(42); // l'erreur étant ici: la liste est copiée.
    a.removeElementFromList(w);
    Bref, tu ne devrais pas exposer ta liste, mais plutôt fournir les fonctions de recherche qui ont du sens histoire de garder de la cohérence.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut
    Merci pour vos réponses. Voici mon code source en entier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <list>
    class A{
    	public:
    		void removeElementFromList(std::list<int>::const_iterator it)
    		{
    			list.erase(it);
    		}
    	private:
    		std::list<int> list;
    };
     
    int main(){
    	return 0;
    }
    Compilé avec g++:
    greg@greg-laptop:/home/greg$ g++ test.cpp
    test.cpp: In member function ‘void A::removeElementFromList(std::_List_const_iterator<int>)’:
    test.cpp:7: error: no matching function for call to ‘std::list<int, std::allocator<int> >::erase(std::_List_const_iterator<int>&)’
    /usr/include/c++/4.4/bits/list.tcc:107: note: candidates are: std::_List_iterator<_Tp> std::list<_Tp, _Alloc>::erase(std::_List_iterator<_Tp>) [with _Tp = int, _Alloc = std::allocator<int>]
    /usr/include/c++/4.4/bits/stl_list.h:1092: note: std::_List_iterator<_Tp> std::list<_Tp, _Alloc>::erase(std::_List_iterator<_Tp>, std::_List_iterator<_Tp>) [with _Tp = int, _Alloc = std::allocator<int>]
    La fonction erase avec un const_iterator n'existe pas d'après http://www.cplusplus.com/reference/stl/list/erase/ .

    Bref, tu ne devrais pas exposer ta liste, mais plutôt fournir les fonctions de recherche qui ont du sens histoire de garder de la cohérence.
    En effet, c'est pas top comme solution mais je ne vois pas de bonne solution pour ce que je veux faire. En fait, ma classe qui contient la liste est une forme geométrique:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class FormeGeometrique{
    public:
    // methodes...
    private:
    std::list<Triangle> triangles;
    }
    Ensuite, j'ai plusieurs algorithmes qui peuvent modifier cette forme géométrique. Pour que ces algos puissent fonctionner correctement, j'ai besoin de leur fournir la liste des triangles et la possiblitée d'ajouter ou supprimer des triangles. Comment faire ça proprement ?

    Merci d'avance.

  7. #7
    Membre expérimenté
    Homme Profil pro
    Consultant BigData
    Inscrit en
    Juillet 2009
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Consultant BigData

    Informations forums :
    Inscription : Juillet 2009
    Messages : 129
    Par défaut
    Citation Envoyé par zenux Voir le message
    La fonction erase avec un const_iterator n'existe pas d'après http://www.cplusplus.com/reference/stl/list/erase/ .
    Pour altérer le contenu de la list, il faut utiliser un iterator et non const_iterator.

    Avec un const_iterator, tu ne peux pas modifier le container (ajout/suppression) ni modifier le contenu de l'un de ses éléments. C'est pour cela qu'il n'existe aps de méthode erase prenant un const_iterator.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut
    Parfait, on est donc d'accord sur ce point .
    On en revient donc à la question initiale: comment encapsuler correctement une liste tout en fournissant un accès en lecture à cette liste + fonction d'ajout et de suppression ?

  9. #9
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 287
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 287
    Par défaut
    Oups.
    J'ai tellement trouvé ce comportement aberrant que j'ai voté négatif. Et pourtant ... c'est bien ce que l'on trouve dans le standard de 98/03.
    Au temps pour moi donc -- vu que l'on ne peut pas annuler un vote (d'ailleurs si un modo passait par là...)

    [À ma décharge, cette aberration a été fixée pour le prochain standard]

    Sinon, zenux, tu peux exposer une interface réduite de la liste (-> begin/end (ou autre équivalent à base de ranges), ce qui ne change pas grand chose au fond. Ton truc reste une liste quelque part si je comprends bien.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

    Informations professionnelles :
    Activité : aucun

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

    Pour encapsuler correctement une collection, tu dois commencer par... ne jamais permettre à l'utilisateur de la récupérer d'une quelconque manière.

    L'idéal étant même de "cacher" le type de collection réellement manipulé à l'utilisateur.

    Pour y arriver, il est donc intéressant de définir dans la classe:
    • des alias de type sur les itérateurs constants et non constant de ta liste (ou de toute autre collection)
    • Les fonctions begin et end en version constante et non constante (si cela a du sens)
    • Les fonctions d'ajout et de retrait d'un élément de la liste (si cela a du sens)
    • Les fonctions de recherche d'un élément en version constante et non constante. (si cela a du sens)
    • Eventuellement (si cela a un sens) un constructeur de la classe prenant un "range" d'éléments capable de s'adapter aux itérateurs de n'importe quelle solution.
    • Les fonctions de manipulations qui t'intéressent

    Au final, ta classe ressemblerait à quelque chose comme
    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
    class MaClass
    {
        public:
            // un type d'itérateur en version non constante (facultatif)
            typedef std::list<Element>::iterator iterator;
            // un type d'itarateur en version constante (plus ou moins obligatoire)
            typedef std::list<Element>::const_iterator const_iterator;
            // un constructeur "sympa" utilisant des iterateurs
            template <typename iter>
            MaClass(iter b, iter e):items_(b,e){}
            // les fonctions begin et end en version constante
            const_iterator begin() const{return items_.begin();}
            const_iterator end() const{return items_.end();}
            // les fonctions begin et end en version non constante (facultatif)
            iterator begin(){return items_.begin();}
            iterator end(){return items_.end();}
            // les fonctions d'ajouts et de suppression (selon besoins)
            void push_fron(Element const & e){items_.push_front(e);}
            void push_back(Element const & e){items_.push_back(e);}
            void insert(iterator i, Element const & e){items_.insert(i,e);}
            template <typename it>
            void insert(iterator i, it b, it e){items_.insert(i,b,e);}
            void erase(iterator it){items_.erase(it);}
            void erase(iterator b, iterator e){items_.erase(b,e);}
            // la fonction de recherche en version constante 
            const_iterator find(Un_type const & value) const
            {
                const_iterator it=items_.begin();
                while(it!=items_.end())
                {
                    if(it->getValue()==value)
                        return it;
                    ++it;
                }
                return items_.end();
            }
            // la fonction de recherche en version non constante (si utile)
            iterator find(Un_type const & value) 
            {
                iterator it=items_.begin();
                while(it!=items_.end())
                {
                    if(it->getValue()==value)
                        return it;
                    ++it;
                }
                return items_.end();
            }
            // quelques fonctions qui seront toujours utiles 
            size_t size() const{return items_.size();}
            bool empty() const{return items_.emty();}
        private:
            std::list<Element> items_;
    };
    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

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2006
    Messages
    396
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 396
    Par défaut
    Merci beaucoup.
    J'aime bien l'idée de cacher le type de la collection grâce à un typedef.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    C'est effectivement une idée des plus sympathiques...

    En effet, tant que tu gardera la même interface pour la classe et que tu veillera à utiliser des collections compatibles (car certains types de collection ne présentent pas certaines fonctions), tu pourra à tout moment décider de changer la manière dont ta classe manipule effectivement les différents éléments sans avoir besoin de retoucher au code qui utilise la classe.

    Cela te permet donc de travailler en accord avec le principe OCP (Open Close Principle : un code doit être ouvert à l'évolution, mais fermé à la modification).

    Cela te permet également de respecter la loi Demeter qui a pour but de t'inciter à n'exposer que "le stricte minimum requis" pour tes classes.

    Dans le cas présent, tu arrives à n'exposer que les fonctions qui sont absolument nécessaires à la gestion des éléments au sein de la classe, sans avoir besoin d'exposer... la collection elle-même, ce qui te permet d'éviter les copies inutiles ainsi que le fait que l'utilisateur ne la manipule de manière "non prévue"
    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

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

Discussions similaires

  1. une liste dans une liste?
    Par JerryOne3 dans le forum C#
    Réponses: 11
    Dernier message: 11/01/2009, 16h43
  2. quand je selectionne une valeur dans une liste, retourne une autre valeur
    Par nsqualli dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 29/12/2008, 14h23
  3. [débutant] Comment gérer une liste dans une liste
    Par Lenoiche dans le forum iReport
    Réponses: 0
    Dernier message: 16/07/2008, 10h41
  4. champ d'une liste lié à une liste dans un autre site
    Par guintolli dans le forum SharePoint
    Réponses: 8
    Dernier message: 08/07/2008, 14h51
  5. Appel d'une liste dans une liste (JSTL)
    Par abalgue dans le forum Hibernate
    Réponses: 4
    Dernier message: 15/06/2007, 10h56

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