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 :

Type erasure et accesseurs


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Profil pro
    Dev
    Inscrit en
    Mai 2009
    Messages
    257
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Mai 2009
    Messages : 257
    Par défaut Type erasure et accesseurs
    Bonjour, j'ai mis en place le pattern type erasure en C++, c-a-d que je masque une classe template avec une classe abstraite

    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 Base{
     
         virtual ~Base(){}
     
         //méthodes virtuelles pures
    }
     
    template<typename T>
    class Derived : Base{
     
    Derived<T>(){}
    ~Derived(){}
     
    //méthodes publiques
     
    private :
    vector<T> datas;
     
    }
    problème : si je veux faire récupérer ou modifier datas, je dois passer par Base

    comment dois je définir les accesseurs getDatas() et SetDatas(vector<T> datas) ?

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

    Informations professionnelles :
    Activité : aucun

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

    Pose toi déjà la question de savoir si tu as réellement besoin des mutateurs et accesseurs

    Dans bien des cas, on se rend compte qu'il est peu intéressant de proposer des accesseur (getData) et encore moins de proposer des mutateurs (setData), surtout lorsque le membre "visé" par l'opération est un conteneur

    N'oublie pas que le propre de la programmation OO (enfin, l'un des aspects principaux, car ce n'est pas le seul ) consiste à envisager un objet sur base des services que l'on attend de lui, et non des données qu'il manipule, les données manipulées n'étant, en définitive, utilisées par l'objet seulement pour lui permettre de rendre les services attendus.

    De ce point de vue, il est déjà excessivement rare de constater qu'un accesseur soit utile, et c'est encore pis au niveau des mutateurs

    Ceci dit, le gros problème avec le type erasure, c'est que tu perdra de toutes manières... l'information de type lorsque tu l'utilisera.

    Tu pourrais donc, effectivement, placer différentes fonctions permettant d'ajouter, de retirer ou de modifier certains éléments de ton vecteur dans ta classe template, 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
    template<typename T>
    class Derived : Base{
    public:
        typedef typename std::vector<T>::iterator iterator;
        typedef typename std::vector<T>::const_iterator const_iterator; 
        Derived<T>(){}
        ~Derived(){}
         void add(T const & t){datas.push_back(t);}
        iterator begin() {return datas.begin();}
        iterator end() {return datas.end();}
        const_iterator begin() const{return datas.begin();}
        const_iterator end() const{return datas.end();}
        size_t size() const{return datas.size();}
     
    private :
    vector<T> datas;
    };
    Mais tu ne pourra pas y accéder directement au départ de ta classe base.

    Si il faut que tu puisse y accéder, tu devra, par exemple, envisager le recours au pattern visitor
    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 très actif
    Profil pro
    Dev
    Inscrit en
    Mai 2009
    Messages
    257
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Mai 2009
    Messages : 257
    Par défaut
    Intéressant, effectivement manipuler directement datas se révèle difficile et délicat

    exploiter les possibilités de la STL (iterator) m'avait échappé

    si je veux modifier datas par adresse sous forme &datas[0], j'utilise begin, c'est ça ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    On peut ajouter un opérateur [] en version constante et non constante, si tu le souhaite...

    Cela te ferais modifier ta classe template 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
    template<typename T>
    class Derived : Base{
    public:
        typedef typename std::vector<T>::iterator iterator;
        typedef typename std::vector<T>::const_iterator const_iterator; 
        Derived<T>(){}
        ~Derived(){}
         void add(T const & t){datas.push_back(t);}
        iterator begin() {return datas.begin();}
        iterator end() {return datas.end();}
        const_iterator begin() const{return datas.begin();}
        const_iterator end() const{return datas.end();}
        T& operator[](size_t i){return datas[i]:}
        T const & operator[] (size_t i) const {return datas[i]:}
        size_t size() const{return datas.size();}
     
    private :
    vector<T> datas;
    };
    Cependant, il faut comprendre que l'utilisation d'itérateurs représente souvent une approche bien meilleure, surtout si tu propose de toi-même un alias de type imbriqué dans la classe.

    En effet, les itérateurs fournissent une interface "uniformisée" pour parcourir les différents éléments d'une collection.

    De ce fait, tant que tu travailles avec des collections "compatibles" (std::vector, std::list, std::set, par exemple), tu peux parfaitement envisager de modifier le type de la collection sans que cela n'implique le moindre changement dans le code utilisateur

    De plus, quand c'est applicable, il est souvent préférable d'utiliser le traitement par "paquet" ou par "écart" (j'hésite réellement sur la traduction à donner à "range") quand c'est possible.

    La possibilité d'obtenir un itérateur sur le premier élément et un autre sur ce qui suit le dernier, et éventuellement un itérateur sur un objet donné (fonction find() ) est alors souvent suffisant
    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

  5. #5
    Membre très actif
    Profil pro
    Dev
    Inscrit en
    Mai 2009
    Messages
    257
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Mai 2009
    Messages : 257
    Par défaut
    en fait en parlant d'adresse, je parle de l'adresse du vector en lui-même

    je pensais que begin en était un équivalent

    ça m'évite de renvoyer un void*

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    La question que tu dois te poser, c'est: pourquoi voudrais tu récupérer l'adresse "de départ" de ton vecteur.

    Ou, plutôt: Quel intérêt aurais tu à essayer d'encapsuler un vecteur si c'est pour en arriver à l'exposer "comme si de rien n'était"

    Pour répondre à ta question, la fonction begin() renvoie un itérateur sur le premier élément du vecteur.

    S'il est vrai qu'un itérateur présente une interface fort proche de celle que l'on observe avec les pointeurs (possibilité de le déréférencer avec l'étoile * ou la flèche ->, possibilité de l'incrémenter), il faut comprendre que ce n'est pas un pointeur pour autant.

    La différence principale tenant dans le fait qu'il s'agit d'un type totalement particulier, différent du type de donnée réellement utilisé
    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. Contourner le Type Erasure des collections
    Par scheme dans le forum Langage
    Réponses: 4
    Dernier message: 18/02/2011, 16h00
  2. Réponses: 29
    Dernier message: 20/09/2009, 06h27
  3. utilisation du meta type ANY
    Par Anonymous dans le forum CORBA
    Réponses: 1
    Dernier message: 15/04/2002, 12h36

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