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 :

héritage et surcharge


Sujet :

Langage C++

  1. #1
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut héritage et surcharge
    Bonjour,

    J'ai une classe parente avec 2 méthodes setRect, prototype différent. Dansd une classe fille je surcharge l'une. Avec une instance de la classe fille j'appelle la méthode non surchargée de la parente, et j'ai une erreur 'method 'A' does not take 4 arguments'.

    Sauriez-vous pourquoi ?

    (je n'ai volontairement pas mis de code car je ne penses pas que cela soit nécessaire, mais si vous voulez un exemple concret dites le moi et je posterais cela)
    Nullius in verba

  2. #2
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Peut-être un problème de masquage de fonction ?

  3. #3
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Effectivement ça a l'air d'être ça... ça veut dire qu'en surchargeant une méthode sur n définies (de même nom) dans la classe mère, je masque les n méthodes ? Pas top ça..

    Merci Cob59 et merci la FAQ dvp

    Je penses qu'on peut considérer le problème résolu.
    Nullius in verba

  4. #4
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    J'aimerais vraiment savoir si "ça veut dire qu'en surchargeant une méthode sur n définies (de même nom) dans la classe mère, je masque les n méthodes ?" est le comportement défini par la norme ou si c'est un "undefined behavior laissé à la guise des créateurs de compilo... vous avez une idée ?
    Nullius in verba

  5. #5
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Kaamui Voir le message
    J'aimerais vraiment savoir si "ça veut dire qu'en surchargeant une méthode sur n définies (de même nom) dans la classe mère, je masque les n méthodes ?" est le comportement défini par la norme ou si c'est un "undefined behavior laissé à la guise des créateurs de compilo... vous avez une idée ?
    Defini. A noter que c'est une question d'imbrication de portee et en rien propre aux classes, le meme comportement existe avec des namespaces et des blocs imbriques (mais pour les blocs, c'est rare car ceux qui s'amusent a y declarer des fonctions sont rares aussi).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  6. #6
    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,

    C'est un comportement parfaitement décrit dans la norme :

    Pour pouvoir surcharger une fonction, il faut:
    • qu'elle soit déclarée virtuelle
    • qu'elle présente exactement la même signature dans la classe dérivée que dans la classe de base.

    Si la fonction n'est pas déclarée virtuelle dans la classe de base, la norme précise qu'il y a "masquage" de la fonction de la classe de base.

    Si la signature n'est pas identique à celle qui se trouve dans la classe de base mais que la fonction de la classe de base est déclarée virtuelle, tu "rajoutes" simplement une fonction supplémentaire (de même nom mais avec des arguments différents). Au temps pour moi, j'ai dit une bêtise ici...

    Maintenant, on peut réellement se poser plusieurs questions :
    1. Pourquoi tiens tu à fournir un mutateur sur le rectangle sous-jacent à ta classe, au mépris de la loi de Déméter
    2. Pourquoi voudrais tu fournir à l'utilisateur la possibilité de modifier le rectangle sous-jacent sous une forme différente dans la classe dérivée
    La première question devrait t'inciter à considérer le niveau d'encapsulation de ta classe car, le simple fait de fournir un mutateur implique que les modifications du rectangle sous-jacent peuvent intervenir n'importe où et que tu laisses la responsabilité à l'utilisateur de ta classe de vérifier que le rectangle qu'il veut défini soit cohérent par rapport à ta classe.

    Cela n'ira pas sans poser un certain nombre de problèmes car toute décision susceptible de modifier la manière dont le rectangle sous-jacent est représenté dans ta classe impliquera de nombreux changements, sur lesquels tu n'as strictement aucun contrôle à l'heure actuelle.

    La deuxième question devrait t'inciter à réfléchir à l'intérêt réel qu'il y a à fournir, dans la classe dérivée uniquement, une possibilité supplémentaire d'appliquer le changement.

    Pourquoi rendre l'interface publique de ta classe dérivée plus inutilement plus complexe, alors que tu disposes déjà d'une solution pour appliquer le changement n'est-ce pas d'une certaine manière contrevenir à l'ISP (Interface Segregation Principle) qui te conseille de garder des interfaces les plus simples possibles Dans le pire des cas, pourquoi ne pas donner cette possibilité supplémentaire directement dans la classe de base Après tout, c'est bien elle qui prend la responsabilité de la gestion du rectangle sou-jacent... Pourquoi voudrais tu "l'amputer" d'une partie de cette responsabilité
    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

  7. #7
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    J'ai une classe Qt qui contient deux méthodes setRect :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    void	setRect ( const QRectF & rect );
    void	setRect ( qreal x, qreal y, qreal width, qreal height );
    Ma classe dérivée doit effectuer une vérification avant d'appeler le sectRect parent...

    Je comprends parfaitement qu'il y ait masquage de fonction sur la fonction que j'ai redéfini puisque c'est ce que je voulais, mais je m'attendais pas à ce que l'autre fonction (non surchargée) soit elle aussi masquée.

    Certes dans mon cas précis ça m'a protégé (et tu viens de m'aider à me rendre compte qu'on a probablement pas respecté LSP puisque notre classe est censée représenter des ellipses ou des cercles (forme particulière d'ellipse)), mais dans d'autres cas ça pourrait être ennuyeux je trouve :/

    Le problème est qu'en l'occurence, Qt ne fournit pas de classe pour les cercles, donc je suis bien obligé de me rabbattre sur les ellipses pour gérer cette demande => donc obligé de surcharger setRect => donc étonné de voir qu'une surcharge masque les n fonction de même nom de la classe mère
    Nullius in verba

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Ceci est du code valide:

    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
    struct s1 {
        int i;
        int f();
    };
     
    struct s2: s1 {
        double i;
        int f(double);
    };
     
    namespace n1 {
    int i;
    int f();
     
    namespace n2 {
    double i;
    int f(double);
    }
    }
     
    void f() {
        int i;
        int f();
     
        {
            double i;
            int f(double);
        }
    }
    et le meme que les double i masquent les int i (ce dont je doute que ca te surprennes a partir du moment ou tu sais que les classes sont considerees comme des portees imbriquees), les int f(double) masquent les int f().
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  9. #9
    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
    Citation Envoyé par Kaamui Voir le message
    Le problème est qu'en l'occurence, Qt ne fournit pas de classe pour les cercles, donc je suis bien obligé de me rabbattre sur les ellipses pour gérer cette demande => donc obligé de surcharger setRect => donc étonné de voir qu'une surcharge masque les n fonction de même nom de la classe mère
    Si ce n'est que ta classe Circle (ou n'importe quoi d'autre) ne peut pas plus hériter de ta classe Elipse qu'une classe Square ne pourrait hériter d'une classe Rectangle

    Tu te retrouves dans les deux cas avec des invariants beaucoup plus forts pour les classes Square et Circle, dans le sens où tu en arrives toujours à un invariant du genre de width == height, et que c'est en contradiction avec la règle qui veut que les invariants de la classe mère soient respectés dans la classe fille.

    C'est, d'une certaine manière, le plus gros reproche que je pourrais faire à Qt : ne pas respecter la loi de Déméter en de nombreuses occasions, bien que je comprenne parfaitement la raison qui pousse à en arriver à ce point.

    Comme tu ne peux pas surcharger les fonctions setRect (qui, autant que je le sache, ne sont pas virtuelles), tout ce que tu pourrais faire, c'est envisager de faire dériver une classe CheckedElipse de la classe Elipse et qui exposerait une fonction isCircle() qui vérifie que la hauteur du rectangle sous-jacent est bien égale à sa largeur (ou, selon le cas, qui vérifie que le diametre horizontal correspond bien au diamètre vertical).

    autre solution consisterait créer une fonction libre qui vérifie que les dimensions concordent, proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    bool isValidForCircle(QRect const & rect){
        return rect.width() == rect.height();
    }
    Mais ce serait de toutes manières toujours à l'utilisateur de faire la vérification, de préférence a priori pour éviter les modifications indues
    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

  10. #10
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    (ce dont je doute que ca te surprennes a partir du moment ou tu sais que les classes sont considerees comme des portees imbriquees)
    ça me surprends

    Citation Envoyé par koala01 Voir le message
    Comme tu ne peux pas surcharger les fonctions setRect (qui, autant que je le sache, ne sont pas virtuelles)
    Je ne peux que les masquer, mais je pensais pouvoir n'en masquer qu'une (je pensais que la totalité de la signature d'une fonction faisait office "d'identité", pas juste son nom...)

    Citation Envoyé par koala01 Voir le message
    tout ce que tu pourrais faire, c'est envisager de faire dériver une classe CheckedElipse de la classe Elipse et qui exposerait une fonction isCircle() qui vérifie que la hauteur du rectangle sous-jacent est bien égale à sa largeur

    [...]

    autre solution consisterait créer une fonction libre qui vérifie que les dimensions concordent, proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    bool isValidForCircle(QRect const & rect){
        return rect.width() == rect.height();
    }
    Mais ce serait de toutes manières toujours à l'utilisateur de faire la vérification, de préférence a priori pour éviter les modifications indues
    ça ne ferait pas que décaler le pb ? Et pourquoi le mot "exposer" ?
    Nullius in verba

  11. #11
    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
    Citation Envoyé par Kaamui Voir le message
    ça ne ferait pas que décaler le pb ?
    Tout dépend de ta manière d'utiliser les différents objets.

    Si tu travailles en respectant "correctement" l'idiome Model View Controller, cela aura au moins l'avantage de limiter ce genre de vérification à un seul module tout en indiquant clairement à l'utilisateur qu'il est important que cette vérification soit faite
    Et pourquoi le mot "exposer" ?
    Pour faire la distinction entre les fonctions membres publiques et celles qui se trouvent dans des niveaux d'accessibilité plus restreints, tout simplement.

    J'aurais pu écrire une phrase proche de "qui définirait la fonction machin dans l'accessibilité publique", mais c'est beaucoup plus long à écrire et je suis du genre fainéant
    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

  12. #12
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Pour pouvoir surcharger une fonction, il faut:
    • qu'elle soit déclarée virtuelle
    • qu'elle présente exactement la même signature dans la classe dérivée que dans la classe de base.
    Tu confonds redéfinition et surcharge.

  13. #13
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    @Kaamui: Ce n'est pas étonnant si tu considères que ce n'est qu'une question de portée comme l'a dit Jean-Marc. Quand tu appels une fonction, le compilateur détermine un ensemble de portée de départ où rechercher la fonction (juste le nom, l'accessibilité et la signature ça vient après). Si il ne trouve pas dans cet ensemble il remonte dans les portées parentes.

    C'est ce qui se passe pour les fonctions membres, tu as un objet d'une certaines classe (type statique), il va rechercher ta fonction dans cette classe, si il trouve le nom il s'arrête, dans ton cas il trouve directement le setRect déclaré dans la classe fille donc il s'arrête.

    Edit: Si tu tiens à réimporter les fonctions de la classe mère dans la portée de la classe fille, utilise un using Mere::foo; dans ta classe fille (partie publique).

  14. #14
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Kaamui Voir le message
    et de meme que les double i masquent les int i (ce dont je doute que ca te surprennes a partir du moment ou tu sais que les classes sont considerees comme des portees imbriquees)
    ça me surprends
    C'est un peu (beaucoup même) le principe de l'imbrication de portée le fait que des définitions internes masquent les définitions externes.

    Je ne peux que les masquer, mais je pensais pouvoir n'en masquer qu'une (je pensais que la totalité de la signature d'une fonction faisait office "d'identité", pas juste son nom...)
    Le principe est qu'on fait une recherche et qu'on arrête celle-ci une fois le nom trouvé. Puis on cherche la meilleure fonction avec ce nom en appliquant une série de règles relativement complexes à cause des conversions implicites, arguments par défaut et de la possibilité de templates de fonction à instancier.

    A noter qu'il n'y a pas d'arguments très fort pour dire que dans le cas des fonctions on ne pourrait pas collecter toutes les surcharges avant de choisir. De mémoire dans D&E (j'ai pas le bouquin ici) Stroustrup dit qu'outre le fait que c'est plus homogène (on traite tous les identificateurs de la même façon -- en passant au moment où on cherche les définitions, on n'a aucune idée si c'est une définition de fonction, de variable, de template, de type... qu'on va trouver) c'est pour éviter des problèmes que d'autres modifications introduites depuis éviteraient maintenant. Je suppose que quand on s'en est rendu compte, changer cet aspect de la collecte des fonctions à surcharger aurait causé trop de problèmes.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  15. #15
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Merci pour ces superbes réponses (où vous allez chercher toutes ces connaissances si précises, parce que j'aimerais les avoir aussi )

    Il faudrait rajouter un bouton "Résolu de manière exhaustive" Merci en tout cas je comprends mieux un tas de chose : encore un exemple du fait que je serais bien incapable de me passer de ce superbe forum !

    @Koala01, malheureusement le projet est assez énorme déjà (reprise de maintenance) et même s'il a une base assez bien codée, les différentes mains qui sont passées dessus ensuite ont fini par rendre le code assez ingérable et les pattern implémentés n'ont pas du tout été respectés. C'est un logiciel open-source du nom d'Open-Sankoré si vous voulez en savoir plus
    Nullius in verba

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 08/02/2008, 14h58
  2. [Problème] Héritage et surcharge
    Par kamykaze dans le forum C++
    Réponses: 8
    Dernier message: 13/11/2007, 14h18
  3. [POO] Héritage et surcharge de méthodes
    Par defkid dans le forum Langage
    Réponses: 4
    Dernier message: 26/02/2007, 14h51
  4. héritage et surcharge
    Par babar63 dans le forum C++
    Réponses: 7
    Dernier message: 17/01/2007, 23h23
  5. [G++] Héritage et surcharge de fonction
    Par Beuss dans le forum Autres éditeurs
    Réponses: 11
    Dernier message: 15/05/2006, 09h18

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