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 :

implantation d'un conteneur "spécialisé"


Sujet :

C++

  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 303
    Billets dans le blog
    2
    Par défaut implantation d'un conteneur "spécialisé"
    Bonjour à tous,

    voilà, j'ai un petit problème intéressant qui se pose à moi, et il me semble qu'il esxiste plusieurs façons de procéder. J'aimerais donc avoir l'avis d'un maximum de personnes avant de faire mon choix.

    La problématique est la suivante:
    je dois développer un tableau, qui ressemblera fort au std::vector, à ceci près que:
    1/ Tous les objets qui seront contenus dans ce tableau héritent d'une même classe dont certains champs sont connus. Il y a notamment un champ "name" de type string.
    2/ Je dois rajouter quelques fonctionnalités "personnalisées", comme par exemple, récupérer un sous-tableau de tous les objets dont le champ "name" commence par une lettre donnée.
    3/ Je tiens à implémenter un itérateur qui me permettra de parcourir ce tableau, ainsi qu'un opérateur de recopie pour le tableau.
    4/ Tous les objets qui seront contenus dans ce tableau héritent d'une même classe, oui, mais ils risquent d'être assez différents, et d'hériter à plusieurs niveaux d'héritage.

    Voilà, je pense que tout ce qui est important pour la conception est là. J'ai une petite idée de comment m'y prendre, mais je suis sûr que les votres seront meilleures

    Merci pour vos propositions.

    r0d.

  2. #2
    Invité
    Invité(e)
    Par défaut
    std::map<std::string, ValType> ?

  3. #3
    Membre Expert
    Avatar de Ti-R
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Avril 2003
    Messages
    1 683
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2003
    Messages : 1 683
    Par défaut
    Pourquoi meilleur, et meilleur que quoi ?

    Lance toi, expose ton point de vu

    Vu que le problème est bien posé, je ne pense pas qu'il y ait vraiment de problème.

  4. #4
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 303
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par toxcct
    std::map<std::string, ValType> ?
    oui bon, avec ça je pourrai faire la fonction dont je parle dans mon post, mais j'ai d'autres fontions plus farfelues à implémenter.
    En fait, je pense qu'il va falloir que créé une classe et que je la fasse hériter de std::vector. Mais est-ce possible? Est-ce la bonne solution?

  5. #5
    Invité
    Invité(e)
    Par défaut
    oui oui, hériter de std::vector est tout a fait possible, mais pour moi, d'apres ta description, tu as l'air d'avoir un tableau, donc plus que une seule dimension (d'ou ma proposition pour map<>).

  6. #6
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Hériter d'un conteneur de la STL est intéressant pour construire des conteneurs au fonctionnement quasi identique au conteneur de base.
    Si après il faut redéfinir des méthodes du conteneur initial, en ajouter qui n'ont rien à voir avec celui ci ou ne jamais en utiliser certaines, enlève le bénéfice de l'héritage.
    Dans ce cas il vaut mieux redéfinir un conteneur complètement nouveaux même si il faut réimplémenter les allocations mémoires et certaines fonctions de base.

  7. #7
    Membre expérimenté Avatar de BertrandA
    Inscrit en
    Août 2003
    Messages
    170
    Détails du profil
    Informations forums :
    Inscription : Août 2003
    Messages : 170
    Par défaut
    Les destructeurs des conteneurs STL ne sont pas virtuels, choix d'implémentation.
    Je trouve cet argument suffisant pour ne pas utiliser un conteneur comme classe de base : je privilégierais plutôt la composition.

  8. #8
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    Mon conseil. Si tu as une interface bien particulière : tu vas devoir définir ton propre conteneur. Ca OK.
    Après, si tu veux disposer de la grande majorité de l'interface d'un autre conteneur (même l'intégralité), tu peux soit composer, soit dériver de façon privée pour réinjecter, à coups de using, les fonctions "parentes" dans l'interface de la nouvelle classe. C'est un hack pour faineants quand l'interface est vraiment très similaire. Et surtout, dans ton cas, ne pas dériver publiquement des conteneurs de la SL (ou de boost). Ils seront là pour t'aider à définir ta classe. Pas pour servir de types auxquels ton conteneur sera subtituable.

    L'héritage public est un hack qui introduit un couplage très fort pas toujours très heureux. Si jamais tu veux changer ta structure interne pour avoir un boost::multi_index car tu auras deux critères de recherche indépendents, avec un héritage tu es cuit, tu peux tout réécrire.

    Dans tous les cas, oublie définitivement l'héritage public. Il ne sert pas à ça.
    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...

  9. #9
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 303
    Billets dans le blog
    2
    Par défaut
    Ok, alors va pour la composition. Le seul point "négatif" est que je dois tout re-implémenter (push_back, at, delete, etc...). Ce n'est pas un problème de fainéantise, mais de qualité. Il ne faut pas se leurrer: je ne saurais jamais refaire tout ça aussi bien que la STL ou boost.

  10. #10
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    Pourquoi réimplémenter ?
    Réutilise ! La composition est faite pour ça.
    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...

  11. #11
    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 : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Ok, alors va pour la composition. Le seul point "négatif" est que je dois tout re-implémenter (push_back, at, delete, etc...). Ce n'est pas un problème de fainéantise, mais de qualité. Il ne faut pas se leurrer: je ne saurais jamais refaire tout ça aussi bien que la STL ou boost.
    Pourquoi "tout ré-implémenter" ? Si tu utilises un conteneur dans ta classe c'est justement pour ne pas tout ré-implémenter.

  12. #12
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 398
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 398
    Par défaut
    Mais il doit reproduire l'interface de chaque fonction, par contre.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  13. #13
    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 : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Mais il doit reproduire l'interface de chaque fonction, par contre
    Pas avec l'héritage privé.

    En gros, pour résumer la solution, ce sera quelque chose comme ça (les deux solutions sont quasiment équivalentes) :

    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
    // Héritage privé
     
    class MonConteneur : private std::vector<Truc*>
    {
    public :
     
        // Importe tout ce que tu veux de std::vector<Truc*>
        typedef std::vector<Truc*> super;
        using super::at;
        using super::erase;
        ...
     
        // Ajoute tes fonctions
        void MaFonction(Truc* t)
        {
            // ...
            push_back(t);
        }
    };
    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
    // Composition
     
    class MonConteneur
    {
    public :
     
        // Fournis une interface pour tout ce que tu veux reprendre de std::vector<Truc*>
        Truc* at(std::size_t i) {return myVector.at(i);}
        std::vector<Truc*>::iterator erase(std::vector<Truc*>::iterator i) {return myVector.erase(i);}
        ...
     
        // Ajoute tes fonctions
        void MaFonction(Truc* t)
        {
            // ...
            myVector.push_back(t);
        }
     
    private :
     
        std::vector<Truc*> myVector;
    };

  14. #14
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 303
    Billets dans le blog
    2
    Par défaut
    Oui, j'ai dit une bêtise. J'ai juste l'interface à implementer, ce qui ne pose pas de problème. Peut-être une perte de performances tout de même?

    [edit]Sinon, Laurent, d'aprés toi, est-il préférable d'utiliser l'héritage privé ou la composition?
    Sinon, je n'ai pas bien compris pourquoi l'héritage public ne conviens pas ici.[/edit]

  15. #15
    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 : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Oui, j'ai dit une bêtise. J'ai juste l'interface à implementer, ce qui ne pose pas de problème. Peut-être une perte de performances tout de même?
    Pas spécialement (inlining, etc...). Et puis si c'était le cas ce ne serait pas vraiment une grosse gêne, si ?

    Sinon, Laurent, d'aprés toi, est-il préférable d'utiliser l'héritage privé ou la composition?
    Je dirais l'héritage privé, qui demande mois d'effort pour ramener les fonctions du conteneur dans l'interface publique de ta classe. A part ça c'est fonctionnellent équivalent.

    Sinon, je n'ai pas bien compris pourquoi l'héritage public ne conviens pas ici.
    Les raisons ont déjà été données dans cette discussion

  16. #16
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 303
    Billets dans le blog
    2
    Par défaut
    Oui, mais je ne les ai pas comprises

    En fait, j'avais cru comprendre que le problème de l'héritage était que si jamais je souhaite changer de classe de base (passer d'un vector à une map par exemple), il me faudrait modifier toute ma classe. Mais j'ai l'impression, au vu de ce qui vient d'être dit, que j'ai compris de travers. Et puis je ne vois pas, dans le cas présent, en quoi l'héritage public est différent de l'héritage privé

  17. #17
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    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 296
    Par défaut
    Avec l'héritage (public ou privé+réinjection), changer de conteneur fait changer l'interface publique de ta classe et donc le code client. Avec l'encapsulation, ben ... c'est encapsulé, le conteneur utilisé en sous-main n'est plus qu'un détail d'implémentation.

    Sinon,
    * héritage public => pour être utilisé en place de, dans du code existant -> mots clé: "Principe de Subsitution de Liskov", "is-a" (/"est-un")
    * héritage privé => pour réutiliser du code existant -> mots-clé "has-a", "defined-in-terms-of" (je crois).

    Avec l'héritage public, ta classe devra être utilisable partout où un vecteur pouvait être utilisé. Faut pas s'amuser à se dire que la classe serait en fait un vecteur trié, cela ne marcherait pas. Elle peut par contre être impléméntée à partir d'un vecteur que l'on maintiendrait toujours trié.
    Sans parler qu'il suffit qu'une fonction prenne un vecteur par copie pour avoir de la perte d'informations. Avec l'héritage privé, faire ce genre de choses ne te viendrait même pas à l'idée car ta classe ne serait-pas-un vecteur.
    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...

  18. #18
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 303
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 303
    Billets dans le blog
    2
    Par défaut
    Ok, je comprend.

    Variment beaucoup

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

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