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 :

3 questions sur une classe


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 32
    Points : 30
    Points
    30
    Par défaut 3 questions sur une classe
    Bonjour,

    Un exemple tiré du livre Le langage C++ est à l'origine des 3 questions de ce message. Voici tout d'abord le code de la déclaration de la classe concernée:
    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
     
    const int TailleDefaut = 10;
    class Array
    {
    public:
     
       Array(int taille = TailleDefaut);
       Array(const Array &rhs);
       ~Array(){delete[] pType;}
       Array& operator=(const Array&);
       int& operator[](int indice);
       cont int& operator[](int indice) const;
       int getTaille() const{return saTaille;}
       friend ostream& operator<<(ostream&, const Array&);
     
       class xLimits {};
     
    private:
     
       int* pType;
       int saTaille;
     
    };
    1er question:
    Concernant la fonction amie operator<<(...), vu qu'elle n'a besoin d'accéder qu'aux données privées de la classe Array, n'est-il pas plus judicieux d'en faire une fonction membre de la classe ? Je croyais que les fonctions amies étaient surtout utiles lorsqu'une classes avait besoin d'accéder aux données privées d'une autre classe, comme le ferait une classe matrice et une classe vecteur pour faire le produit d'une matrice par un vecteur.

    2ème question:
    Concernant le fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const int& operator[](int indice)
    , pourquoi ne pas renvoyer un int plus simplement ? Il est vrai que dans le livre d'où est tiré cet exemple, l'auteur avait créé auparavant une classe générique ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <class T> class Array{...}
    La même fonction pour le type T au lieu du type int avait pour prototype:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const int& operator[](int indice)
    Je comprends alors mieux le type retourné par cette fonction qui évite une copie de l'objet T en renvoyant une référence sur le type T, le qualificatif const empêchant de modifier la valeur référencée.
    Mais dans le cas d'un int, comment expliquer cette valeur de retour ?

    3ème question:
    Voici la définition partielle de la fonction membre operator[] de la classe Array:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int& Array::operator[](int indice)
    {
     
       ...
       throw xLimits();
       return pType[0]; // pour MFC
     
    }
    Cette fonction membre va-t'-elle effectivement renvoyer pType[0] si l'exception xLimits est renvoyée ? Cela supposerait qu'après l'envoi de l'exception xLimits, la fonction operator[] reprenne la main. Or, il me semblait que c'était le bloc catch() correspondant à cette exception qui reprenait la main immédiatement après l'envoi de l'exception.
    Le commentaire "pour MFC" qui fait référence aux Microsoft Fondation Class est peut-être une partie de la réponse à mon questionnement.

    Merci de m'éclairer sur ces questions de débutant qui ne remettent pas en cause la qualité de l'ouvrage cité.

  2. #2
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    1/ Échec du livre. En faite, on est obligé de passer par une fonction comme définit en friend (car l'opérateur agit sur un ostream, pas sur this), mais je n'aime pas cette façon de faire.
    Une meilleur façon est de definir un write(ostream), et si on tient à l'opérateur<<(osteam,obj), on chaine l'appelle à write.

    2/ [FALSE]Gros échec, inutile... ça en revient au même >< (en tout cas à l'écriture du bouquin). [/FALSE] Interfaçage C.

    3/ un throw termine la fonction. Le return ne sera pas évalué.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Baubeau Cédric Voir le message
    Bonjour,

    1er question:
    Concernant la fonction amie operator<<(...), vu qu'elle n'a besoin d'accéder qu'aux données privées de la classe Array, n'est-il pas plus judicieux d'en faire une fonction membre de la classe ? Je croyais que les fonctions amies étaient surtout utiles lorsqu'une classes avait besoin d'accéder aux données privées d'une autre classe, comme le ferait une classe matrice et une classe vecteur pour faire le produit d'une matrice par un vecteur.
    Ce que tu cite est l'une des conséquences de l'amitié, lorsqu'elle s'applique à une clase...

    Une autre des conséquences de l'amitié, lorsqu'elle s'applique à des fonctions, et de permettre, justement, de "sortir" la fonction de la classe dont elle est déclarée amie...

    Le but étant, justement, si tu as une variable de type Array proche de
    Array a(15);
    de ne pas devoir accéder à ton opérateur depuis ta variable a (selon l'exemple) sous la forme de
    mais bien de pouvoir utiliser la syntaxe "classique"
    2ème question:
    Concernant le fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const int& operator[](int indice)
    , pourquoi ne pas renvoyer un int plus simplement ?
    Pour un type primitif, on peut, effectivement, se poser la question
    Il est vrai que dans le livre d'où est tiré cet exemple, l'auteur avait créé auparavant une classe générique ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    template <class T> class Array{...}
    La même fonction pour le type T au lieu du type int avait pour prototype:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const int& operator[](int indice)
    Je comprends alors mieux le type retourné par cette fonction qui évite une copie de l'objet T en renvoyant une référence sur le type T, le qualificatif const empêchant de modifier la valeur référencée.
    Dans le cas d'un type "indéterminé", c'est, effectivement, la manière la plus sensée de travailler, pour la raison que tu présente
    Mais dans le cas d'un int, comment expliquer cette valeur de retour ?
    On pourrait dire qu'il n'y a aucun avantage à renvoyer une référence constante sur un type primitif, mais, d'un autre coté, il n'y a pas d'inconvénient notable non plus...

    Maintenant, va savoir si c'est une distraction de la part de l'auteur, une erreur commise lors de la traduction (si traduction il y a eu) ou si c'était délibéré de la part de l'auteur...
    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
    3ème question:
    Voici la définition partielle de la fonction membre operator[] de la classe Array:
    
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    123456789
     
    int& Array::operator[](int indice)
    {
     
       ...
       throw xLimits();
       return pType[0]; // pour MFC
     
    }
    Cette fonction membre va-t'-elle effectivement renvoyer pType[0] si l'exception xLimits est renvoyée ?
    Non, tout ce qui se trouve "au delà" du lancement d'une exception est purement et simplement ignoré si elle est lancée

    Le lancement d'une exception agit, à peut de chose près, comme si tu fermait l'ensemble des accolades pour mettre prématurément fin à la fonction (et au fonctions appelantes qui ne disposent pas du bloc catch adéquat)
    Cela supposerait qu'après l'envoi de l'exception xLimits, la fonction operator[] reprenne la main. Or, il me semblait que c'était le bloc catch() correspondant à cette exception qui reprenait la main immédiatement après l'envoi de l'exception.
    Non, non, tu as bien compris le principe de fonctionnement des exceptions
    Le commentaire "pour MFC" qui fait référence aux Microsoft Fondation Class est peut-être une partie de la réponse à mon questionnement.
    (MFC...Quelle horreur...)

    Il n'est pas *impossible* qu'il y ait un problème dans les MFC au niveau du lancement d'exceptions, et que, dans ce cas, il faille alors... renvoyer le premier élément du tableau

  4. #4
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 282
    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 282
    Points : 11 036
    Points
    11 036
    Par défaut
    2/ permet de donner un accès à la donnée interne.
    Suppose que tu aies une fonction f() qui prennent un "int const*" en paramètre, et bien avec un simple "Array a; ..... f(&a[0]);" c'est possible.
    Aussi étrange soit-il l'intérêt de s'interfacer avec des fonctions C est bien réel.

  5. #5
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Effectivement, au temps pour moi. En C++03 pure, ça me semble vraiment inutile, pas la même chose en c++0x et en interfaçage c.

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 32
    Points : 30
    Points
    30
    Par défaut
    Merci pour vos réponses. J'ai compris pour la fonction amie et vous me confortez dans mon opinion concernant les deux autres questions.

    Cependant, pour reprendre l'exemple de Luc concernant le type &a[0], c'est un int* et non pas un int&. Je sais qu'une référence peut être assimilée à un pointeur constant auquel on applique l'indirection, mais le compilateur ne fait-il pas la différence ?

  7. #7
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 282
    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 282
    Points : 11 036
    Points
    11 036
    Par défaut
    a[0] donne un accès direct au premier int du tableau à l'intérieur de la classe -- vu que l'on renvoie une référence.
    &a[0] est donc un pointeur vers ce premier int...

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Si ton opérateur [] retourne un int, alors a[0] retourne une copie de ton premier élément et &a[0] prend l'adresse de la variable 'implicite' utilisée pour le retour par valeur --> erreur.
    Si ton opérateur[] retourne une référence int &, alors a[0] est une référence vers le premier élément du tableau. Donc &a[0] pointe vers la même adresse que le premier élément du tableau.

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 32
    Points : 30
    Points
    30
    Par défaut
    OK, j'ai bien compris la différence entre un retour de type int et un retour du type int&. Je pensais (j'avais lu un peu rapidement) que dans l'exemple donné par Luc, la fonction f() attendait comme argument un int& et non un int const*, d'où ma précédente question.

    Encore merci de votre aide.

Discussions similaires

  1. Réponses: 2
    Dernier message: 28/02/2011, 09h45
  2. [POO] Questions sur une classe get
    Par beegees dans le forum Langage
    Réponses: 8
    Dernier message: 10/05/2007, 10h40
  3. Question sur une classe <template>
    Par Pingva dans le forum C++
    Réponses: 1
    Dernier message: 26/01/2007, 17h16
  4. Réponses: 14
    Dernier message: 14/03/2005, 09h16
  5. [MFC] Problème pointeur sur une classe
    Par mick74 dans le forum MFC
    Réponses: 7
    Dernier message: 14/04/2004, 14h17

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