Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 10 sur 10
  1. #1
    Membre régulier
    Inscrit en
    novembre 2006
    Messages
    350
    Détails du profil
    Informations forums :
    Inscription : novembre 2006
    Messages : 350
    Points : 79
    Points
    79

    Par défaut Attribut classe mère initialisé dans dérivées

    Bonjour a tous,

    J'ai un petit probleme, une classe de Base dont dérivent X objets.
    Chaque objet possede une map<string, string> propre a lui meme.

    Par contre l'initialisation de cette map et son utilisation est commune a tout les objets. Je voulais donc mettre tout les traitements de cette map dans ma classe de base.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Base
    {
    protected:
        static std::map<std::string, std::string> _dicoParam;
        void initDico( void ); // Init commune du dico
    };
    class Fille: public Base
    {
    ...
    }
    Et dans le cpp de mes filles
    Code :
    1
    2
     
    std::map<std::string, std::string> Fille::_dicoParam= {{"A","B"},{"C","D"}}
    Mais l'initialisation d'un membre static ne peut pas etre faite dans les derivees.
    Y a t il un moyen de faire quelque chose dans cet esprit ?

    Merci d'avance

  2. #2
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 691
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 691
    Points : 15 768
    Points
    15 768

    Par défaut

    Salut,

    Attends, j'aimerais être sur de comprendre...

    Ton membre _dicoParam doit il etre rempli une bonne fois pour toute, indépendamment de l'instance de la classe fille utilisée, ou veux tu simplement que chaque classe fille présente une fonction initDico de manière à pouvoir profiter du polymorphisme (ce qui fait que chaque classe dérivée pourra initialiser le membre avec ses propres données).

    Dans le premier cas, tu fais bien d'utiliser une variable statique, mais c'est un membre de la classe parent, ce qui fait que tu devrait "simplement" remplacer Fille::_dicoParam par Base::_dicoParam

    Dans le deuxième cas, la classe Base n'a, a priori, pas besoin de disposer du membre _dicoParam ou, en tous cas, pas sous une forme statique (et si elle dispose de dicoParam, il faudra sans doute la placer dans l'accessibilité protégée, ce qui, personnellement, me dérange quand meme un peu ).

    Par contre, il faudra déclarer la fonction initDico comme étant virtuelle (éventuellement virtuelle pure, si Base ne dispose pas du membre _dicoParam ), pour pouvoir réimplémenter son comportement dans les classes dérivées.

    Ceci dit, ce n'est qu'un détail, mais l'underscore " _ " comme préfix est réservé à l'implémentation du compilateur.

    Si tu veux distinguer les membres d'une classe, tu devrais décider de le placer en suffixe (sous la forme de dicoParam_ ), par exemple
    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

  3. #3
    Membre régulier
    Inscrit en
    novembre 2006
    Messages
    350
    Détails du profil
    Informations forums :
    Inscription : novembre 2006
    Messages : 350
    Points : 79
    Points
    79

    Par défaut

    Bonjour et merci pour ta reponse.

    C'est la deuxieme solution du coup oui je n'y ai pas pensé mais ca ne pourra pas marcher car chaque instance filleA filleB a son propre paramDico.
    En fait mon initialisation du dico est dependant de ma classe fille, par contre l'utilisation qui en est faite est commune.

    Du coup je me suis pris la tete pour rien,
    Je declare mon Dico dans ma classe mere, avec une methode traiteDico commune et une methode initDico virtuelle.
    Chaque fille l'implemente en fonction de ses données.
    Si je ne declare pas Dico dans la mere, le traiteDico ne pourra pas etre commun (ou je me trompe, y a t il une solution ?)

    C'est l'habitude de vouloir tout initialiser via vecteur d'init que j'ai zappe une simple methode d'init..

  4. #4
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 088
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 088
    Points : 5 128
    Points
    5 128

    Par défaut

    Citation Envoyé par sone47 Voir le message
    Si je ne declare pas Dico dans la mere, le traiteDico ne pourra pas etre commun (ou je me trompe, y a t il une solution ?)
    C'est bien ça. Il y aurait des solutions, mais ça n'aurait pas vraiment de sens. C'est la logique de l'héritage public: ce que possède la classe de base est également possédé par toutes ses classes dérivées, mais pas l'inverse.
    Si tu veux mettre des objets que dans les classes dérivées, alors ça n'a pas de sens de vouloir manipuler ces objets à un niveau supérieur. Tu peux déclarer les contrats (ou le protocole, ou comme vous voudrez l'appeler) au niveau supérieur, mais pas l'implémentation.

    Sinon, bien souvent la nécessité d'une fonction Init cache une erreur de conception. Je te propose de lire cette faq.

  5. #5
    Membre régulier
    Inscrit en
    novembre 2006
    Messages
    350
    Détails du profil
    Informations forums :
    Inscription : novembre 2006
    Messages : 350
    Points : 79
    Points
    79

    Par défaut

    Ok merci,
    Je suis parti sur une piste ou le constructeur de chaque instance fille fait appel à initDico().
    Mais j'ai du mal a voir mon problème de conception, ce que je pourrais faire c'est ne rien mettre dans la mère et tout déporter dans les classe dérivées mais si je change un traitement du dico je vais devoir tout me frapper toutes les modifs pour chaque fille...
    Je pensais que ça simplifiait justement le code.

  6. #6
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 088
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 088
    Points : 5 128
    Points
    5 128

    Par défaut

    Appeler la fonction Init dans le constructeur est une bonne solution, tant que cette fonction Init est privée (ou protégée).

    Si cette initialisation est différente selon chaque classe fille, un simple template method suffit:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Mere
    {
    public: 
       Mere() { Init(); } // constructeur qui appelle Init()
     
    protected:
       virtual void Init() = 0;
    };
     
    class Fille : public Mere
    {
    private:
       void Init() { /* l'implémentation ici */ }
    };

  7. #7
    Membre régulier
    Inscrit en
    novembre 2006
    Messages
    350
    Détails du profil
    Informations forums :
    Inscription : novembre 2006
    Messages : 350
    Points : 79
    Points
    79

    Par défaut

    Ok merci pour ces précisions,
    C'est exactement ce que j'ai fais.
    Question bete mais c'est quoi un "template method"?

  8. #8
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 088
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 088
    Points : 5 128
    Points
    5 128

    Par défaut

    template method (ou patron de méthode) est un design pattern (ou patron de conception). Ce sont des schémas qui définissent un agencement de classes dans le but de résoudre des problèmes courants lorsqu'on programme en utilisant des objets (programmation orientée objet, poo). Jette un coup d'oeil ici, c'est le template method. Ca peut paraître compliqué à première vue, mais en fait c'est très simple et très utile.

  9. #9
    Modérateur

    Homme Profil pro Cyrille
    Network programmer
    Inscrit en
    juin 2010
    Messages
    2 083
    Détails du profil
    Informations personnelles :
    Nom : Homme Cyrille
    Âge : 27
    Localisation : France

    Informations professionnelles :
    Activité : Network programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 2 083
    Points : 4 905
    Points
    4 905

    Par défaut

    Malheureusement ceci est impossible.
    Mere est construit avant Fille, et Mere n'a aucune connaissance de Fille.
    L'appel d'une méthode virtuelle dans le constructeur apelle son implémentation dans la classe actuelle (ou une classe mère, en aucun cas dans sa classe Fille).

    Si ce genre de procédés est nécessaire, il faut faire l'initialisation en 2 temps:
    Code :
    1
    2
    Fille* pFille = new Fille;
    pFille->Init();

  10. #10
    r0d
    r0d est déconnecté
    Expert Confirmé Sénior

    Profil pro
    Inscrit en
    août 2004
    Messages
    4 088
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : août 2004
    Messages : 4 088
    Points : 5 128
    Points
    5 128

    Par défaut

    oops en effet, tu as raison
    En fait, je suis justement en train de travailler sur une architecture qui permet ça, mais en passant par du p_impl et du clone(); du coup j'avais oublié que ce n'était pas si direct.

    D'ailleurs, un peu de bonne lecture

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •