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 :

Fabrique de template


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Août 2002
    Messages
    225
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 225
    Points : 118
    Points
    118
    Par défaut Fabrique de template
    Salut tout le monde !

    Je bloque sur un problème de conception. Je dois faire une fabrique de template. Histoire de clarifier un peu les choses, voici, en gros, ce que je dois faire.

    Soit IBase une classe de base déclarée comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class IBase
    {
    private:
    // constructeur par recopie et opérateur d'affectation
     
    public:
        IBase();
        virtual ~IBase();
    };
    Soit une classe ITBase déclarée comme suit :
    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
     
    template <typename T>
    class ITBase : public IBase
    {
    private:
    // constructeur par recopie et opérateur d'affectation
     
    public:
        ITBase(const T& data);
        virtual ~ITBase();
        virtual void OnPrint() const = 0;
        T& GetData() const;
     
    protected:
        T _data;
    };
    ... et enfin, soit une classe TBaseImpl déclarée comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template <typename T>
    class TBaseImpl : public ITBase<T>
    {
    private:
    // constructeur par recopie et opérateur d'affectation
     
    public:
        TBaseImpl(const T& data);
        virtual void OnPrint() const;
    };
    Bon, les noms des classes sont bidons mais c'est juste pour donner une idée représentative d'une partie de la hiérarchie des classes que je dois gérer.

    J'aimerai implémenter une fabrique qui, à partir d'une chaîne de caractère, me renvoie une instance de ITBaseImpl, un peu de la façon suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class TFactory
    {
    public:
        template <typename T> ITBase<T>& GetAReference(std::string& rTypeName);
    };
    Les contraintes sont les suivantes :
    * <T> peut être un type parmi de nombreux (un peu plus de 100 types possibles dans mon cas).
    * je n'ai pas la possibilité d'utiliser d'autres librairies que les librairies système de Linux et ACE (exit donc boost, loki et autres librairies susceptibles d'apporter une réponse à mon problème)
    * les types <T> sont des structures que je ne peux pas modifier

    En partant du principe que toutes les instances possibles de TBaseImpl<T> sont instanciées et stockées dans ma fabrique, que la dite fabrique remplie le contrat de la méthode GetAReference, comment faire pour résoudre simplement le problème de la création de toutes les instances de TBaseImpl<T> ?

    La solution nulle consiste à laisser la fabrique créer chaque instance et à les stocker dans une map dont la clé est une chaine de caractère. Cette solution ne me convient pas car :
    * c'est long et pénible à faire
    * la fabrique est impactée à chaque ajout / suppression d'un type <T>

    J'ai lu dans différents articles sur le forum que la méta programmation résoud ce problème mais je suis obligé de me faire tout le code (voir dans les contraintes pourquoi) et vu mon niveau c'est un peu trop compliqué.

    Est ce que quelqu'un(e) a une idée pour m'aider à trouver une solution correcte ?

    D'avance merci.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 071
    Points : 12 116
    Points
    12 116
    Par défaut
    système de Linux et ACE (exit donc boost, loki et autres librairies susceptibles
    Là, vous êtes dans la mauvaise parti du forum, ici c'est C++ pour .NET donc C++/CLI donc Windows ou Mono sous Linux.

    On ne fait pas un conteneur IoC sur un coin de table. Utilisez les librairies connexes sera bien plus rentable. A vous de montrer que vous maîtrisez les éventuelle dépendances induites. Cela sera bien plus simple.

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Si j'ai bien compris, ta fabrique doit pouvoir te renvoyer un objet de n'importe quel type dérivé sur base d'une chaine de caractères qui serait susceptible de représenter le type que tu attend

    Si tel est le cas, tu devrais rendre ta classe de base clonable en:
    1. rendant placant le constructeur de TBaseImpl dans l'accessibilité protégée ou privée
    2. déclarant ta fabrique comme amie de ta hiérarchie de classe (pour qu'elle ait accès au constructeur
    3. créant une fonction virtuelle "clone" qui renverra un pointeur vers une toute nouvelle instance de la classe (allouée dynamiquement).
    Cela te donnerait un code 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
    32
    33
    34
    35
    36
    37
    class IBase
    {
        public:
           /* pour que l'on puisse détruire un objet passant pour être de type
            * IBase
            */
            virtual ~IBase();
            virtual IBase* clone() const = 0;
        protected:
            Base(){} //pour que seules les classes dérivées y aient acces
    }
    template <class T>
    class ITBase : public IBase
    {
        protected:
            ITBase(T const & data):data(data){} //idem que pour IBase
            /* si T est défaut constructible */
            ITBase(){}
            T data;
    };
    template<class T>
    class TBaseImpl : public ITBase<T>
    {
        private:
            friend class Factory; // pour que Factory puisse accéder à tout :D
            TBaseImpl (T const & d):ITBase<T>(d){}
            /* si T est défaut constructible */
            TBaseImpl(){}
        public:
            virtual TBaseImpl * clone() const
            {
                /* si T est défaut constructible */
                return new TBaseImpl();
                /* sinon */
                return new TBaseImpl(this->data);
            }
    };
    et tu maintient, à l'intérieur de ta fabrique, un tableau associant une chaine de caractère à tes différentes classes dérivées (en fait, une std::map pour laquelle la clé est une std::string et la valeur est un pointeur sur IBase) et qui est susceptible de créer tes instances:
    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
    class Factory
    {
        /* pour la facilité d'écriture, à usage interne uniquement */
        typedef std::map<std::string, IBase *> map;
        typedef map::iterator iterator;
        typedef map::const_iterator const_iterator;
        public:
            Factory()
            {
                items_.insert(std::make_pair("type1", newTBaseImpl<Type1>));
                items_.insert(std::make_pair("type2", newTBaseImpl<Type2>));
                items_.insert(std::make_pair("type3", newTBaseImpl<Type3>));
                items_.insert(std::make_pair("type4", newTBaseImpl<Type4>));
                items_.insert(std::make_pair("type5", newTBaseImpl<Type5>));
                /*...*/
            }
            template<class T>
            IBase * create(std::string const & n, T const & d) const;
            {
                const_iterator it=items_.find(n);
                /* si le type n'est pas trouvé, on sort d'ici */
                if(it=items_.end())
                    return 0;
                TBaseImpl<T> *temp= (*it).second->clone();
                temp->data = d;
            }
            /* il ne faut pas oublier de libérer correctement la mémoire 
             * allouée à tous les pointeurs lorsqu'on détruit la fabrique
             */
             ~Factory()
             {
                 for(iterator it=items_.begin();it!=items_.end();++it)
                 {
                     delete (*it).second;
                 }
             }
        private:
            map items_.
    }
    *idéalement*, il faudrait bien sur veiller à ce que cette fabrique ne soit disponible que sous la forme d'une instance unique (singleton inside ) pour éviter qu'elle ne soit créée et détruite à chaque fois que l'on souhaite créer un type donné
    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. [Templates] Quel système utilisez-vous ? Pourquoi ?
    Par narmataru dans le forum Bibliothèques et frameworks
    Réponses: 270
    Dernier message: 26/03/2011, 00h15
  2. Template XHTML
    Par Sylvain James dans le forum XSL/XSLT/XPATH
    Réponses: 14
    Dernier message: 16/06/2003, 21h45
  3. appliquer plusieurs templates
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 04/04/2003, 16h26
  4. template match="node() mais pas text()"
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 26/03/2003, 10h52
  5. [XSLT] template
    Par demo dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 09/09/2002, 11h31

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