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 :

Surcharge de l'opérateur d'indexation


Sujet :

C++

  1. #1
    Membre expérimenté
    Profil pro
    Étudiant
    Inscrit en
    Avril 2007
    Messages
    181
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2007
    Messages : 181
    Par défaut Surcharge de l'opérateur d'indexation
    Bonjour,

    J'ai un problème avec la surcharge de l'opérateur d'indexation.
    J'ai appris en cours les deux exemples de prototypes à utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int& operator[](int); // écriture
    int operator[](int) const; // lecture
    Pour les besoins d'un projet où la STL est partiellement interdite (seul les headers iostream, fstream, et string sont autorisés), je cherche à reproduire un conteneur associatif avec des couples key/item (limité aux types string/int).
    J'ai créé une classe Dict (par analogie avec le type dict en Python), dont voici le header :
    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 <string>
     
    typedef std::string KeyType;
    typedef int ItemType;
     
    class Dict
    {
    public:
        // ...
     
        // ajout d'un nouveau couple key/item,
        // ou nouvelle valeur de l'item si new_key existe déjà
        ItemType& operator[](KeyType new_key);
     
        // recherche d'un item à partir d'une clef
        // une exception est levée si la clef n'existe pas
        ItemType operator[](const KeyType& key) const;
     
        // ...
    Un arbre binaire est utilisé pour stocker les couples key/item.
    Le but recherché est de pouvoir écrire dans le code client :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Dict d;
    // accès en écriture
    d["test"] = 7;
    d["essai"] = 52;
    d["test"] = 0; // 7 est écrasé
    // accès en lecture
    int i = d["essai"]; // i = 52;
    Le problème est que la dernière ligne de code appelle aussi la méthode d'ajout, et non celle de recherche (comportement confirmé par des cout dans les méthodes).
    Du coup, si la clef existe, une référence vers l'item associé est retournée (au lieu d'être dupliqué).
    Et si la clef n'existe pas, la méthode retourne une valeur indéfinie (au lieu de lever une exception).
    Que dois-je modifier pour différencier l'appel de la méthode de recherche de la méthode d'ajout ?

    Merci.

  2. #2
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    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 292
    Par défaut
    Ta supposition comme quoi l'accès non contant est un accès en écriture et l'autre en lecture est fausse. Le const va servir à choisir quelle fonction utiliser selon la mutabilité officielle de ta donnée depuis la portée où tu la manipules.
    Si la données est officiellement non modifiable, alors l'opérateur const sera employé. Sinon, ce sera toujours l'autre. Même si tu veux seulement lire.

    Si tu veux vraiment distinguer les types d'accès, il faut passer par des proxys.
    Sinon, tu fais comme pour std::map: si tu veux un accès juste en lecture, tu fais un find pour obtenir un itérateur.
    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...

  3. #3
    Membre expérimenté
    Profil pro
    Étudiant
    Inscrit en
    Avril 2007
    Messages
    181
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2007
    Messages : 181
    Par défaut
    Les solutions proposées m'étant totalement inconnues (j'apprends le C++ depuis peu), je n'ai pas beaucoup avancé.
    Je ne comprends pas ce que tu veux dire par :
    Citation Envoyé par Luc Hermitte
    Sinon, tu fais comme pour std::map: si tu veux un accès juste en lecture, tu fais un find pour obtenir un itérateur.
    Pour le type map de la STL, l'opérateur d'indexation est surchargé qu'une seule fois (j'ai regardé dans le header), mais je ne cherche pas à reproduire exactement map : si la clef n'existe pas lors d'une recherche, je veux lever une exception.
    Ce que je veux obtenir est d'ordre purement syntaxique : utiliser la forme
    aussi bien en ajout (écriture) qu'en recherche (lecture).
    Sinon je peux toujours remplacer la méthode de recherche par un simple get :
    et cela marche très bien.
    Mais j'aimerais avoir la syntaxe avec les crochets pour les deux opérations, juste pour la « beauté » du code...

    En ce qui concerne les classes « proxy », je n'en avais jamais entendu parler auparavant. J'ai trouvé quelques exemples intéressants pour simuler l'opérateur [][] :

    Mais je ne vois pas comment faire pour appliquer ce principe à ma classe Dict :
    Quel serait le type intermédiaire pour le proxy ? ItemType ?
    Et quel serait l'opérateur surchargé dans le proxy ?

  4. #4
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 292
    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 292
    Par défaut
    Quand on veut un accès en lecture seule sur une map, on utilise std::map::find, vu que l'opérateur [] modifie la map.

    Sinon, implémentation imparfaite d'une solution imparfaite (les proxys)
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    #include <iostream>
    #include <string>
    #include <vector>
     
    template <typename T> struct Ppt
    {
        Ppt(T & ref) : m_ref(ref) {}
        T& operator=(T const& ref) {
    	std::cout << "(ecrit)";
    	m_ref = ref;
        }
        operator T const& () const {
    	std::cout << "(lit)";
    	return m_ref;
        }
    private:
        T & m_ref;
    };
     
    template <typename T>
    std::ostream& operator<<(std::ostream &os, Ppt<T> & ppt) {
        return os << static_cast <T const&>(ppt);
    }
     
    struct Classe
    {
        Classe()
    	: m_i(0)
    	, m_v(10)
    	, i(m_i)
    	, s(m_s)
    	{}
     
        Ppt<std::string> s2() { return Ppt<std::string>(m_s);}
        Ppt<int> operator[](size_t i) { return Ppt<int>(m_v[i]); }
        int operator[](size_t i) const { return (m_v[i]); }
    private:
        int              m_i;
        std::string      m_s;
        std::vector<int> m_v;
    public:
        Ppt<int>         i;
        Ppt<std::string> s;
    };
     
    int main (int argc, char **argv)
    {
        Classe c;
        std::cout << "affiche i: " << c.i << std::endl;
        std::cout << "change i" << std::endl;
        c.i = 42;
        std::cout << "affiche i: " << c.i << std::endl;
     
        std::cout << "change s" << std::endl;
        c.s = "toto";
        std::cout << "affiche s: ";
        std::cout << c.s ;
        std::cout << std::endl;
     
     
        std::cout << "v[5]==" << c[5] << std::endl;
        std::cout << "v[6]<-12" << std::endl;
        c[6] = 12;
        std::cout << "v[6]==" << c[6] << std::endl;
    }
    Plus d'infos dans la FAQ C++ lite, et encore plus dans More Effective C++
    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...

Discussions similaires

  1. Surcharge de l'opérateur new
    Par :Bronsky: dans le forum C++
    Réponses: 17
    Dernier message: 27/10/2010, 21h33
  2. Réponses: 8
    Dernier message: 29/08/2006, 00h56
  3. [C#] Surcharge de l'opérateur ==
    Par LE NEINDRE dans le forum Windows Forms
    Réponses: 3
    Dernier message: 18/07/2006, 16h19
  4. Réponses: 6
    Dernier message: 12/07/2006, 15h34
  5. Réponses: 15
    Dernier message: 25/01/2005, 16h51

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