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 :

Init const map dans derivee


Sujet :

Langage C++

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut Init const map dans derivee
    Bonjour,

    Je voudrais avoir une classe de base qui oblige ses enfants a definir une const map de string.
    Je cherche a initialiser cette map dans les .h des classes derivees dans un style comme:

    La classe de base
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    // Mere .h
    class Mere
    {
    const std::map<std::string, std::string> maMap;
    };
    Une derivee
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    // FilleA.h
    #include Mere.h
    const std::map<std::string, std::string> Mere::maMap = boost::assign::map_list_of
    ("FilleA", "FilleA");
    class FilleA: public Mere
    {
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    // FilleB.h
    #include Mere.h
    const std::map<std::string, std::string> Mere::maMap = boost::assign::map_list_of
    ("FilleB", "FilleB");
    class FilleB: public Mere
    {
    };
    Est ce qu'il est possible de proceder dans un style comme celui ci ? (juste une init declarative dans les headers des filles)

    Merci d'avance

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    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 288
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    je ne comprend pas ce que tu veux faire, mais déjà, il me semble que tu te trompes sur l'utilisation de static. Si ta map est déclarée static, ça implique qu'elle ne peut exister qu'en un seul exemplaire dans tout ton programme. Or j'ai l'impression que toi tu souhaites avoir une map par instance.

    Mais ton problème n'est pas clair, il faudrait que tu précises plus.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    Par défaut
    Ca ressemble plus à une map par type…

  4. #4
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par sone47 Voir le message
    Bonjour,

    Je voudrais avoir une classe de base qui oblige ses enfants a definir une const map de string.
    Je cherche a initialiser cette map dans les .h des classes derivees dans un
    Hello,

    un attribut static est lié à une classe (tout comme une méthode statique ne peut pas être virtuelle) donc la map sera lié à la Mere et ne sera pas "redéfinie" dans les filles.

    Si tu veux tester que tes filles auront une map<string, string> tu peux faire quelques chose comme ça : (mais tu sera obligé de redéfinir une map dans chaque fille.)
    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
    template <class T, class U>
    struct same_type {
    	static const bool value = false;
    };
     
    template <class T>
    struct same_type<T, T> {
    	static const bool value = true;
    };
     
    class Fille;
     
    template <class T>
    struct has_a_string_string_map {
    	static_assert(same_type<std::map<std::string, std::string>, decltype(T::maMap)>::value, "pas de string string map"); 
    };
     
    class Fille {
    	friend struct has_a_string_string_map<Fille>;
     
    	static std::map<std::string, std::string> maMap;
     
    	has_a_string_string_map<Fille> check; // doit être à la fin
    };
     
    std::map<std::string, std::string> Fille::maMap;

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut
    Bonjour merci pour vos reponses,
    Effectivement le static dans la mere va impliquer une seule map, j'ai mis le code pour expliquer le principe.
    En fait je vais avoir une map par type, dans l'ideal je devrais declarer une static map dans chaque enfant, mais la map est utilisée par la mere c'est pour sa que je voudrais la declarer dans la mere et l'initialiser dans chaque fille.

    Aujourd'hui je fais juste une methode init() dans chaque fille qui initialise la map avec des valeurs desirees.

    Dans l'ideal la map devrait etre const et c'est plutot sur ce point que je bloque:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // Mere .h
    class Mere
    {
    static const std::map<std::string, std::string> maMap;
    };
    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
    // FilleA.h
    #include Mere.h
     
    // Probleme pour initialiser la map ici ??
    const std::map<std::string, std::string> Mere::maMap = boost::assign::map_list_of
    ("FilleA", "FilleA");
    class FilleA: public Mere
    {
    };
     
    // FilleB.h
    #include Mere.h
     
    // Probleme pour initialiser la map ici ??
    const std::map<std::string, std::string> Mere::maMap = boost::assign::map_list_of
    ("FilleB", "FilleB");
    class FilleB: public Mere
    {
    };

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Bonjour,

    conceptuellement parlant, j'ai du mal avec le principe de la classe mère qui utilise quelque chose qui doit être initialisé par la classe fille.
    A quel niveau intervient l'héritage et pourquoi s'encombrer d'un héritage ?

    Je serais bien plus partant pour une liste de Fille, et une classe template qui prend une Fille en paramètre template, Fille ayant l'obligation de définir une const map en static:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Fille1 { static const std::map<> s_map; };
    struct Fille2 { /* rien ici : classe non utilisable avec SupaClass ci-dessous */};
    template< class T >
    struct SpaClass { static void DoStuff() { /* utilisation de T::s_map */ }  };
    Non testé.
    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.

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    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 288
    Billets dans le blog
    2
    Par défaut
    ça parait bizarre à première vue effectivement, mais bon...

    Le problème d'une variable membre const (qu'elle soit statique ou pas), c'est qu'elle doit être initialisée dans la liste d'initialisation du constructeur. Mais dans ton cas, c'est à dire pour une std::map, j'avoue que je ne sais pas si c'est possible.

    Peut-être quelque chose dans le style (en utilisant une map temporaire et la copier):
    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
    class Mere
    {
    public:
    Mere( const map<string,string> & other ) : map_( other ) {};
    const map<string, string> map_;
    };
     
    class Fille: public Mere
    {
    public:
    Fille( const map<string, string> & other) : Mere(other) {};
    };
     
    main()
    {
       map<string,string> other;
       other["foo"] = "bar";
       Fille fille( other );
    }
    (à tester)

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    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 288
    Billets dans le blog
    2
    Par défaut
    Ha non, on me fait signe que ça ne marche pas: on ne peut pas initialiser une variable membre static const dans le constructeur, puisqu'une variable const ne doit être initialisée qu'une fois, et une variable static doit l'être en dehors de la classe.

    Mais franchement, une std:map const, ça me parait compliqué :/
    Pourquoi ne pas l'encapsuler dans une structure et s'arranger pour que cette structure ne soit manipulée que par références constantes?

    De toutes façons, ça n'a pas vraiment de sens ce que tu veux faire. Enfin, je ne le vois pas.

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut
    Ok merci,

    Et bien en fait je voulais changer ça car dans le principe cette map la, c'est juste du declaratif, et c'est pour ca que le header de chaque classe héritante je voulais la remplir.
    Cette map doit contenir des noms de parametres avec des valeurs associées, le soft se sert ensuite de ses valeurs sans jamais la modifier.

    Actuellement ce que je fais c'est que chaque classe heritante a une methode d'init() ou dedans je rentre a la main mes couples de string parametre valeur (la map n'est pas const actuellement).

    Je trouvais plus clair de caler les couples de cette map dans le .h.

    Ou alors je passe par une solution comme r0d a dit, je declare dans le .h de chaque classe fille une static map "declarationParamFilleX" et dans la creation de la fille je lui passe la map, faut que je regarde ce cote la

    Merci

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    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 288
    Billets dans le blog
    2
    Par défaut
    Et pourquoi veux-tu qu'elle soit static cette map?

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut
    Non le static n'a plus lieu d'etre j'ai mis ca dans l'exemple du premier post mais j'avais pas pensé que le static de la mere serait generalisé a toutes les instances filles du coup, ca aurait ete bon en declarant mes map static directement dans les filles.

    En fait c'est juste une const map.

    Je vais le supprimer

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

    Informations professionnelles :
    Activité : aucun

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

    De manière générale, il faut comprendre qu'un membre static:
    • existe une et une seule fois pour toutes les instances de toutes les classes dérivées s'il se trouve dans la classe parent
    • existe une et une seule fois pour toutes les instance de la classe dérivée s'il se trouve dans la classe dérivée (mais chaque classe dérivée peut déclarer le dit membre)

    Du coup:
    • Si toutes les instances de toutes les classes dérivées partagent les mêmes données à la virgule près, rendre le membre static et le placer dans la classe mère
    • Si toutes les instance d'une classe dérivée particulière partagent les même données à la virgule près, tu peux le rendre static et le placer dans la classe dérivée (*)
    • Si chaque instance d'une classe dérivée particulière dispose de ses propres données qui sont (potentiellement) différente d'une autre instance de la même classe dérivée le membre ne doit pas être static (**)(***)(****)

    (*)Si, pour une raison ou une autre, tu dois pouvoir accéder à cet élément commun à toutes les instances d'une classe dérivée particulière depuis une instance d'objet qui "passerait pour être" du type de la classe mère (polymorphisme sur le comportement inside ), l'idéal est de rajouter une fonction virtuelle pure dans la classe mère (car il te serait impossible de fournir un comportement cohérent dans la classe mère ) et de l'implémenter dans toutes les classes filles afin qu'elle fournissent l'accès aux données en question.

    (**) Il faut alors réfléchir au besoin éventuel de disposer de ces informations depuis un objet de type dérivé "passant pour etre" du type de la classe mère:

    Si la gestion des dites données peut décemment être considéré comme l'une des responsabilités de la classe mère, tu peux envisager de placer l'élément dans la classe mère et y rajouter également les comportement de gestion (quitte à les rendre protégés pour que seules les fonctions des classes dérivées puissent y accéder).

    (***)Si la responsabilité de la gestion de l'élément ne peut décemment pas être considérée comme "faisant partie de la responsabilité" de la classe mère, mais que l'on doit pouvoir y accéder depuis tout élément passant pour être du type de la classe mère, on repart sur l'idée d'un comportement polymorphe déclaré au niveau de la classe mère, implémenté dans les classes filles.

    (****)Si tu ne dois jamais accéder à cet élément depuis un objet "passant pour etre" du type de la classe mère, places cet élément (et tous les comportements qui en concernent la gestion éventuelle) dans les classes dérivées, quitte, si tu envisage de gérer les objets de tes classes filles avec des fonctions (ou des classes) génériques (template) à veiller à ce que les noms soient identiques dans toutes les classes dérivées (*****).

    (*****) Dans ce cas particulier (et, de manière générale, si toutes les classes filles doivent avoir un élément particulier identique, mais qui n'a rien à voir avec la classe mère), il est possible (merci C++ de nous permettre cela ) d'envisager de créer deux interfaces différentes, et d'utiliser l'héritage multiple:
    Une interface "classique" (non template, avec fonctions virtuelles si besoin, et tout le paradigme OO à la rescousse) pour la classe mère et une interface template (avec comme paramètre template le type de la classe dérivée) qui apporte "juste le comportement adéquat" supplémentaire, sous une forme proche 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
    24
    25
    26
    27
    28
    29
    30
    31
    class Base
    {
        public:
            Base();
            virtual ~Base();
            /*
    };
    /* déclaré "par ailleurs */
    template <typename Type>
    class TStub
    {
        /* ce qui est commun à toutes les classes dérivées mais qui n'entre
         * pas dans Base (idéalement, une classe comme celle-ci par
         * élément séparé ;))
         */
    };
    class Derivee1 : public Base,
                          public TStub<Derivee1>
    {
     
    };
    class Derivee2 : public Base,
                          public TStub<Derivee2>
    {
     
    };
    class Derivee3 : public Base,
                          public TStub<Derivee3>
    {
     
    };
    Mais, dans quelle situation te trouves-tu
    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

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut
    Bonjour merci pour ce retour!

    J'ai surligné mon cas
    Citation Envoyé par koala01 Voir le message
    • Si toutes les instances de toutes les classes dérivées partagent les mêmes données à la virgule près, rendre le membre static et le placer dans la classe mère
    • Si toutes les instance d'une classe dérivée particulière partagent les même données à la virgule près, tu peux le rendre static et le placer dans la classe dérivée (*)
    • Si chaque instance d'une classe dérivée particulière dispose de ses propres données qui sont (potentiellement) différente d'une autre instance de la même classe dérivée le membre ne doit pas être static (**)(***)(****)

    (*)Si, pour une raison ou une autre, tu dois pouvoir accéder à cet élément commun à toutes les instances d'une classe dérivée particulière depuis une instance d'objet qui "passerait pour être" du type de la classe mère (polymorphisme sur le comportement inside ), l'idéal est de rajouter une fonction virtuelle pure dans la classe mère (car il te serait impossible de fournir un comportement cohérent dans la classe mère ) et de l'implémenter dans toutes les classes filles afin qu'elle fournissent l'accès aux données en question.

    (**) Il faut alors réfléchir au besoin éventuel de disposer de ces informations depuis un objet de type dérivé "passant pour etre" du type de la classe mère:

    Si la gestion des dites données peut décemment être considéré comme l'une des responsabilités de la classe mère, tu peux envisager de placer l'élément dans la classe mère et y rajouter également les comportement de gestion (quitte à les rendre protégés pour que seules les fonctions des classes dérivées puissent y accéder).


    (***)Si la responsabilité de la gestion de l'élément ne peut décemment pas être considérée comme "faisant partie de la responsabilité" de la classe mère, mais que l'on doit pouvoir y accéder depuis tout élément passant pour être du type de la classe mère, on repart sur l'idée d'un comportement polymorphe déclaré au niveau de la classe mère, implémenté dans les classes filles.

    (****)Si tu ne dois jamais accéder à cet élément depuis un objet "passant pour etre" du type de la classe mère, places cet élément (et tous les comportements qui en concernent la gestion éventuelle) dans les classes dérivées, quitte, si tu envisage de gérer les objets de tes classes filles avec des fonctions (ou des classes) génériques (template) à veiller à ce que les noms soient identiques dans toutes les classes dérivées (*****).

    (*****) Dans ce cas particulier (et, de manière générale, si toutes les classes filles doivent avoir un élément particulier identique, mais qui n'a rien à voir avec la classe mère), il est possible (merci C++ de nous permettre cela ) d'envisager de créer deux interfaces différentes, et d'utiliser l'héritage multiple:
    Une interface "classique" (non template, avec fonctions virtuelles si besoin, et tout le paradigme OO à la rescousse) pour la classe mère et une interface template (avec comme paramètre template le type de la classe dérivée) qui apporte "juste le comportement adéquat" supplémentaire, sous une forme proche de
    Mais, dans quelle situation te trouves-tu
    Car dans mon cas:

    Ma classe mere definit la gestion de cette map (en fait elle recherche dans un dictionnaire les couples (string:string) (parametre:valeur) qui sont definis dans cette map.

    Chaque classe dérivée est responsable du contenu de cette map (les donnees sont communes pour toutes les instances derivees)

    Je pourrais le mettre static dans la classe derivee mais je devrais du coup redefinir dans chaque fille la gestion de cette map dans la recherche des couples sur le dictionnaire.. Ce qui est peu elegant.

    Donc actuellement cette map est non const dans la mere, et chaque fille la remplit dans un initMap() (methode virtuelle pure de la mere).

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    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 288
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    en fait, je pense que l'héritage n'a pas lieu d'être dans ton cas.
    1. Du point de vue théorique, l'héritage définit une relation "est-un". Par exemple, chat hérite de animal car en effet, le chat est un animal. Je n'ai pas l'impression que cette relation est vérifiée dans ton cas.
    2. Du point de vue pratique, et on oublie souvent de le dire, la mise en place d'une hiérarchie de classe implique des contraintes et comporte un certain nombre de défauts et difficultés. Par conséquent, avant de décider si on met en place une hiérarchie de classe, il faut regarder ce que cela apporte. Or dans ton cas, je n'ai pas l'impression que ça apporte quoi que ce soit.
    3. Le stockage des données et leur manipulation sont deux choses différentes, et il est préférable de déparer les deux. La tentation est souvent grande de faire un conteneur qui manipule également les données qu'il contient (et nous connaissons tous le mauvais exemple de std::string), mais ce n'est pas une bonne chose. C'est le principe de SRP (single responsability principle). Et si tu regarde les conteneurs de la STL (sauf string donc), le code qui manipule leurs données sont à l'extérieur de ces classes (dans <algorithm> en particulier), à part quelques exceptions.

    Donc c'est toujours pareil, il est difficile de donner des conseils comme ça sans connaître exactement le contexte dans lequel tu te trouves, mais je te conseille de considérer d'autres options. Par exemple:
    - d'un côté une classe qui contient la map (et si la hiérarchie apporte vraiment quelque chose, alors implémenter cette hiérarchie) et qui fournit des fonctionnalités d'accès aux données, mais proprement (iterateurs, operateurs),
    - et de l'autre côté, une classe qui va manipuler ces données en récupérant ces données dans les paramètres de ses fonctions (en utilisant des références), ou par agrégation (ou composition, ça dépend du contexte).

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 643
    Par défaut
    Citation Envoyé par sone47 Voir le message
    Bonjour merci pour ce retour!

    J'ai surligné mon cas


    Car dans mon cas:

    Ma classe mere definit la gestion de cette map (en fait elle recherche dans un dictionnaire les couples (string:string) (parametre:valeur) qui sont definis dans cette map.

    Chaque classe dérivée est responsable du contenu de cette map (les donnees sont communes pour toutes les instances derivees)

    Je pourrais le mettre static dans la classe derivee mais je devrais du coup redefinir dans chaque fille la gestion de cette map dans la recherche des couples sur le dictionnaire.. Ce qui est peu elegant.

    Donc actuellement cette map est non const dans la mere, et chaque fille la remplit dans un initMap() (methode virtuelle pure de la mere).
    Attention, cela aura pour effet que, si Derivee1 et Derivee2 héritent de Base (qui contient la map static), tu auras, au mieux, les informations requises pour Derivee1 ET Derivee2, au pire, les informations relatives à la dernière classe pour laquelle tu as appelé initMap, et ce, pour TOUTES les instances d'objets dérivés de Base

    La conséquence sera d'avoir d'office des informations incohérentes, soit parce que tu te retrouves avec des éléments "en trop" dans ta map, soit parce que tu te retrouves avec des éléments qui ne sont rien d'autre que... des données correspondant à une autre classe dérivée

    Dans tous les cas, ca risque vraiment de ne pas faire ce que tu veux re

    Ceci dit, pour te faciliter la tache, on peut assez facilement utiliser le code que j'ai présenté plus tot pour résoudre le problème, en faisant appel au NVI pattern.

    Ce que je te proposerais bien pour y arriver tient en trois classes (dont deux qui servent de classes de base à tes classes dérivées):

    Ta classe de base, qui met "tout ce qu'il faut" en place pour utiliser le NVI, sous une forme proche de
    Base.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Base
    {
        public:
            virtual ~Base();
            std::string const & find(std::string const & key) const{return doFind(key);}
            void initMap(){doInitMap();}
            /*... les autres fonctions dont tu as besoin ;)) */
        private:
           /* la magie NVI se trouve ici :D */
           virtual std::string const & find(std::string const & key) const =0;
           virtual void doInitMap() = 0;
    };
    Une classe template qui dispose effectivement de la map et qui implémente les comportements des fonctions virtuelles pures:
    MapHolder.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
     
    template <DERIV>
    struct MapFiller;/* (voir plus loin)  */
    template <typename DERIV>
    struct MapHolder
    {
        std::string const & doFind(std::string const & key) const */
        {
            static emptyString("");
            auto it = map_.find(key);
            if(it!=map_.end());
                return it.second;
            return emptyString;
        }
        inline void doInitMap();
        std::map<std::string, std::string> map_; // les données
        bool initialized_; // pour savoir s'il faut remplir la map ou non
    };
    MapHolder_next.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    template <typename DERIV
    void MapHolder<DERIV>::doInitMap()
    {
        /* un peu plus de magie */
        if(!initialized_)
            MapFiller<DERIV>()(map_);
        initialized_ = true;
    }
    Alors, tu te demandes sans doute pourquoi j'ai déporté la fonction doInitMap dans un fichier d'en-tête à part, et ce qu'est ce "MapFiller".

    Le fait est que chaque classe dérivée va disposer de ses propres couples clé / valeur.

    Il faut donc trouver un moyen pour spécialiser le remplissage de la map, pour chaque type dérivé.

    Et ca, ce sera le role de MapFiller.

    Tu auras remarqué que je n'ai fait qu'une déclaration anticipée de MapFiller, mais c'est "tout ce qu'il faut" pour être en mesure de définir une spécialisation (totale, dans le cas présent) de la structure en question, qui n'est ici qu'un simple foncteur.

    Tu pourrais donc envisager de spécialiser MapFiller pour Derivee1 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
    template<>
    struct MapFiller<Derivee1>
    {
        void operator()(std::map<std::string,std::string>& toFill) const
        {
            map["un"] = "one";
            map["deux"] = "two";
            map["trois"] = "three";
            map["quatre"] = "four";
        }
    };
    et, pour Derivee2 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
    template<>
    struct MapFiller<Derivee1>
    {
        void operator()(std::map<std::string,std::string>& toFill) const
        {
            map["salut"] = "hello";
            map["mond"] = "world";
            map["toujours"] = "always";
            map["jamais"] = "never";
        }
    };
    mais le fait est que l'implémentation de doInitMap a besoin de la définition complete de MapFiller (avec la déclaration de l'opérateur () ! )pour travailler.

    On ne pouvait donc pas placer l'implémentation de cette fonction avant d'avoir placé... la spécialisation de MapFiller.

    Maintenant que l'on a ces trois fichiers, "YAPUKA" mettre tout cela en musique dans les fichiers d'en-tête des classes dérivées
    Derivee1.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
    #include <Base.h>
    #include <MapHolder.h>
    class Derivee1; //il faut que le compilateur sache que Derivee1 existe ;)
    template<>
    struct MapFiller<Derivee1> // ce n'est qu'un copier collé de ce que j'ai écrit plus haut ;)
    {
        void operator()(std::map<std::string,std::string>& toFill) const
        {
            map["un"] = "one";
            map["deux"] = "two";
            map["trois"] = "three";
            map["quatre"] = "four";
        }
    };
    class Derivee1 : public Base, // toutes les classes dérivées sont des base
                     private MapHolder<Derivee1> //et sont implémentée en termes de MapHolder
    {
       /* s'il y a encore quelque chose à rajouter */
    };
    #include <MapHolder_next.h> // pour avoir l'implémentation de doInitMap
    Et tu fais bien sur pareil pour chaque classe dérivée

    Et voilà, tu as un comportement polymorphe au niveau de la classe de base qui est correctement redéfini pour chaque classe dérivée en n'ayant que les "points de variation" (ici, le fait de remplir correctement la map) à spécialiser pour tes classes dérivées.

    C'est y pas beau, tout ca

    NOTA: je n'ai pas indiqué l'initialisation des membres statiques de MapHolder, mais je te laisses le soin de t'en occuper
    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

  16. #16
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut
    Merci pour tes explications,
    En fait je ne m’étais jamais trop posé de question sur le sujet,
    C'est d'ailleurs pour ça que quand tu dis "mauvais exemple de std::string" je ne tilt pas trop.. Je vais regarder un peu le sujet sur le srp.

    Donc je pense que par raccourci tout a été inclu dans le meme objet.

    Pour essayer de détailler le contexte,
    Il y a un objet generique calcul, qui recuper des couples parametres/valeurs dans un dico pour ensuite bosser avec.

    Plusieurs classe CalculXXX heritent de ce calcul de base et parmi leurs spécificités ils mettent a jour la map de parametres/valeurs (défini dans calcul).
    Ensuite ils appellent un runCalcul (défini dans calcul vu que c'est commun a tout les calculs qui utilise la map).

    Le problème du coup vient bien de ce que tu dis non ? D'avoir mélanger les 2.

    [EDIT] J'ai posté avant de voir ton message Koala01, merci pour cet exemple détaillé! Je décortique tout ça

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 643
    Par défaut
    Citation Envoyé par sone47 Voir le message
    Merci pour tes explications,
    En fait je ne m’étais jamais trop posé de question sur le sujet,
    C'est d'ailleurs pour ça que quand tu dis "mauvais exemple de std::string" je ne tilt pas trop.. Je vais regarder un peu le sujet sur le srp.
    SRP est l'acronyme de "Single Responsability Principle", ou, si tu préfères en français, "Principe de la responsabilité unique".

    Ce principe est relativement simple: il te dit que chaque chose (que ce soit une classe ou une fonction) ne doit s'occuper que d'une et une seule chose, mais qu'elle doit s'en occuper correctement.

    La classe std::string est en effet un exemple de mauvaise application de srp car elle regroupe à vrai dire trois grands types de responsabilité:
    • La gestion des caractères : tout ce qui a trait à l'ajout ou à la suppression de caractères et au fait de disposer de suffisamment de mémoire pour les placer
    • la manipulation des caractères : toutes les fonctions qui permettent de modifier la chaine de caractères autrement que par simple ajout / suppression

    Donc je pense que par raccourci tout a été inclu dans le meme objet.

    Pour essayer de détailler le contexte,
    Il y a un objet generique calcul, qui recuper des couples parametres/valeurs dans un dico pour ensuite bosser avec.

    Plusieurs classe CalculXXX heritent de ce calcul de base et parmi leurs spécificités ils mettent a jour la map de parametres/valeurs (défini dans calcul).
    Ensuite ils appellent un runCalcul (défini dans calcul vu que c'est commun a tout les calculs qui utilise la map).

    Le problème du coup vient bien de ce que tu dis non ? D'avoir mélanger les 2.
    Oh, mais alors, là, il faut absolument séparer correctement les responsabilités et travailler de manière tout à fait différente!!!

    Là, tu as une première classe qui doit s'occuper de maintenir les informations, (et qui dispose de la fonction runCalcul) et, à coté, une hiérarchie de classe qui s'occupe de rajouter les informations...

    Tu aurais donc quelque chose qui pourrait ressembler à:
    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
    class Calcul;
    class Computer
    {
        public:
            void addCalculInfo(Calcul const &);
            void runCalculs(); 
        private:
            std::map<std::string, std::string> datas_;
    };
    class Calcul
    {
        public:
            virtual void fillMap(std::map<std::string, std::string> & toFill) = 0;
    };
    /* toutes les classes dérivées de Calcul qui rajoutent effectivement les données */
    qui sera utilisée sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main()
    {
        Computer c;
        {
            Calcul1 calc(/* param eventuels */);
            c.addCalculInfo(calc);
        }
        c.addCalculInfo(Calcul2(/* params éventuels*/)); // ca marche aussi
        /* ...*/
        c.runCalcul();
    }
    Maintenant, il faut bien se dire une chose.

    Si l'idée est de faire des calculs, le choix d'introduire les données sous la forme de chaines de caractères ne me semble vraiment pas des plus efficaces à cause de tout ce que cela implique de conversions pour y arriver

    De même, la comparaison entre chaine de caractères étant, par nature, particulièrement lente (et l'étant d'autant plus que les chaines de caractères sont longues), le choix d'une std::string comme clé ne me semble pas des plus opportuns non plus
    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

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

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 288
    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 288
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Si l'idée est de faire des calculs, le choix d'introduire les données sous la forme de chaines de caractères ne me semble vraiment pas des plus efficaces à cause de tout ce que cela implique de conversions pour y arriver

    De même, la comparaison entre chaine de caractères étant, par nature, particulièrement lente (et l'étant d'autant plus que les chaines de caractères sont longues), le choix d'une std::string comme clé ne me semble pas des plus opportuns non plus
    Tu vas peut-être un peu vite en besogne (early optimization is evil)

    Sinon, en fait tu as raison (et j'avais tort) sur un point: il vaut mieux que la hiérarchie soit sur les classes qui manipulent les données que sur celle/celles qui les contient/contiennent. Ça parait tellement évident une fois que c'est bien expliqué

  19. #19
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 366
    Par défaut
    Ok merci pour ces retours!

    Je vais regarder tout ça et essayer de combiner tes 2 posts pour avoir quelque chose de plus maintenable que ce que j'ai actuellement, la tout est beaucoup trop ciblé..
    Concernant le fait de bosser avec des strings, je sais que cela consomme énormément, la question n'a pas été posée au début car le dico de référence est un xml qui défini ces params en string, du coup soit je passe une moulinette dans le code qui spécifie des id pour les params mais ca aurait obliger l'appli a connaitre ces données (faire du déclaratif dans le soft de calcul), soit demander d'associer des id unique dans le xml d'entree mais on n'a pas la main dessus.

    En tout cas merci pour ces infos, j'ai pas mal de sujet a regarder du coup!

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 643
    Par défaut
    Citation Envoyé par r0d Voir le message
    Tu vas peut-être un peu vite en besogne (early optimization is evil)
    Même, tu as raison en disant que l'optimisation prématurée nuit gravement à la santé, le fait de choisir l'outil le plus adapté au travail que l'on doit effectuer n'est jamais de l'optimisation prématurée, mais bien une question de bon sens

    Tu pourrais très bien choisir de manger ta soupe avec une fourchette, mais il faut avouer que, sauf quelques cas qui feraient que ta soupe ressemble plus à une potée qu'à une soupe, le faire avec une cuiller sera beaucoup plus efficace, quoi qu'il advienne

    Ceci dit, au vu du dernier message de sone, je me dis que si l'on peut garder (malgré les inconvénients en terme de comparaison que cela implique) les clés sous formes de chaines de caractères, l'idéal serait quand même malgré tout de trouver le moyen de passer les valeurs dans une moulinette qui les transformerait en données métiers, non

    l'idée sous-jacente étant que, si tu converti directement les chaines de caractères en données métier, tu n'auras à le faire qu'une bonne fois pour toute à la lecture du XML, alors que tu devrais passer ton temps à le faire à chaque utilisation si tu les gardais sous forme de chaines de caractères.

    Mais, je me contente d'inciter cone à réfléchir à ce sujet, libre à lui de le faire ou non
    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. Init d'une const map dans une classe
    Par vdaanen dans le forum SL & STL
    Réponses: 4
    Dernier message: 15/01/2009, 15h03
  2. Sauvegarde std::map dans un fichier
    Par ZeRiL dans le forum SL & STL
    Réponses: 8
    Dernier message: 03/05/2007, 12h54
  3. Integrer google maps dans une application
    Par La Truffe dans le forum API standards et tierces
    Réponses: 4
    Dernier message: 01/11/2006, 16h45
  4. [Image] image map dans des images dynamique?
    Par xtaze dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 19/05/2006, 17h28
  5. Réponses: 6
    Dernier message: 30/04/2004, 15h53

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