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 :

question bete sur les structures en C++


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2013
    Messages : 23
    Points : 28
    Points
    28
    Par défaut question bete sur les structures en C++
    bonsoir,
    j'ai le bout de code suivant et je n'arrive pas a réellement saisir la logique derrière.
    J'ai deux structure A et B. B est public de A et une méthode foo virtuelle dans A et également définie dans B. J'observe que si je fais A* a= new B et que j'appelle a->foo() effectivement la fonction B::foo est appelée mais avec la valeur du paramètre par defaut de A::foo!
    Quelqu'un saurait pourquoi c'est l'argument de la struct A qui est utilisé dans B?

    Merci d'avance pour l'explication.
    PS: j'utilise g++ version 4.7.3
    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
     
    #include<iostream>
    struct A{
      virtual int foo(int x=1){
        std::cout << "in A::foo" << std::endl;
        return x*2;
      }
    };
    struct B: public A{
      int foo(int z=10){
        std::cout << "in B::foo with " << z << std::endl;
        return z*3;
      }
    };
    int main(){
      A *a = new B;
      std::cout << a->foo() << std::endl;
      return 0;
    }
    L'output:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    in B::foo with 1 <--- ok rentre bien dans foo de B! et z=1 et non pas 10!
    3  <-------------------------renvoie z*3 mais utilise pour z la valeur 1 qui est le paramètre par défaut de A::foo!

  2. #2
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Salut,

    C'est parce que l'argument par défaut est décidé à la compilation, ce qui signifie que quand ton compilateur va lire la ligne:

    il va regarder le type de a, qui sera A, et "assigner" l'argument par défaut à ce moment.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2013
    Messages : 23
    Points : 28
    Points
    28
    Par défaut
    Merci pour la réponse. Donc si je comprends bien toute valeur par défaut d'un argument d'une méthode foo d'une classe de base est applique a la méthode foo de la classe dérivée même si cette dernière définit une autre valeur par défaut différente de celle de la classe de base. Ceci n’étant valable que pour les code implémentant : A* a = new B;
    Merci encore pour la clarification. J'ai appris quelque chose.

  4. #4
    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,
    Non, c'est encore plus vicieux que cela...

    Le fait est que le compilateur est un brave petit soldat : il vois un pointeur sur A, il choisit la valeur par défaut pour A, il voit un pointeur sur B, il choisit la valeur par défaut pour B.

    Ainsi, tu auras plutôt le résultat suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A * ptra=new B;
    B * ptrb=new B;
    ptra->foo(); // affiche 1
    ptrb->foo(); // affiche 10
    Ceci dit, d'un point de vue purement conceptuel, l'idée de changer la valeur par défaut pour ta classe dérivée est assez hummmm... embarrassante ... inquiétante , je ne trouve pas vraiment le terme

    Pour t'aider à comprendre mon malaise :

    Il faut savoir que l'héritage est une relation EST-UN au sens littéral du terme.

    Autrement dit, tout objet de type B EST-UN objet de type A, un peu comme une voiture EST-UN véhicule à moteur.

    Du fait de cette relation, tu ne peux pas faire n'importe quoi : Le LSP t'incite à veiller à ce que toute propriété valide pour A soit aussi valide pour B, et bon, ca, tu le respecte à peu près, mais il faut aussi te dire:

    Primo, que si le développeur a jugé bon de placer une valeur par défaut, c'est très certainement qu'il y a bien réfléchi et qu'il avait une très bonne raison pour le faire. Essayer de "supplanter" cette valeur par défaut, revient à nier cette raison.

    Secundo, que le LSP est en réalité basé sur une approche appelée la programmation par contrat.

    Cette approche, si on la simplifie à l'extrême pour l'explication, revient à dire "donne moi ce que je veux, tu auras ce à quoi tu t'attends, mais si tu ne le fais pas, tu peux t'attendre à tout, et surtout au pire".

    Enfin, cette approche s'intéresse au conditions pour que l'exécution puisse se passer correctement, et fait la distinction entre trois grandes catégories:
    1. Les préconditions : ce sont des conditions qui doivent être remplies avant d'essayer de travailler : si tu n'a pas de mortier, tu ne sauras jamais faire tenir tes briques
    2. Les postconditions : ce sont des conditions qui doivent être vérifiées après l'exécution : tu ne devras pas casser ton mur et le recommencer que s'il est bien droit, bien rectiligne et à la bonne hauteur.
    3. et enfin, les invariants : ce sont des choses qui doivent être vérifiées en permanence (mais je n'ai pas d'exemple à te donner pour le mur, mais bon, si tu es un homme, le fait de te raser ou de te laisser pousser les cheveux ne fera pas de toi une femme et inversement )


    Pour que le système fonctionne, tu ne peux pas faire n'importe quoi avec ces conditions parce que tu risques de te retrouver avec un objet de type B qui est sensé être valide mais qui ne remplit pas les conditions pour être un A (ce qui est quand même malheureux ) ou inversement, de te retrouver avec un objet B qui, quand il est considéré comme un A semblerait tout à fait valide mais qui ne serait jamais accepté en tant que B (ce qui serait encore plus malheureux).

    Je sens confusément que tu ne respectes pas les règles en voulant modifier la valeur par défaut de ton argument.

    La meilleure preuve ne est que tu n'obtiens pas du tout le comportement escompté

    Et c'est normal: à partir du moment où une décision de conception est prise, le compilateur n'est absolument pas armé pour pouvoir décider si elle est judicieuse ou non, ce n'est pas son rôle, et il ne saurait pas comment faire.

    Il va donc se contenter de l'appliquer du mieux qu'il peut, et tant pis si le comportement semble aberrant

    Enfin, tout cela pour dire que voilà un excellent signal d'alarme, qui te fait apprendre à peu de frais.

    Parfois, les signaux d'alarmes sont beaucoup plus discrets et les conséquences beaucoup moins agréables
    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
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2013
    Messages : 23
    Points : 28
    Points
    28
    Par défaut
    Merci pour la réponse! en fait ceci fait partie d'un test que j'ai passé et qui incluait des questions de ce genre. J'essaie la après coup de comprendre mes mauvaises réponses. Je fais plus ou moins comme lorsqu'un enseignant vous rend un corrigé et que vous essayez de comprendre pourquoi vous vous êtes mangé afin d’éviter de refaire la même boulette!
    Merci encore.

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

Discussions similaires

  1. [MySQL] question bete sur les boucles
    Par Klink dans le forum PHP & Base de données
    Réponses: 9
    Dernier message: 24/01/2013, 15h18
  2. [Débutant] question bete sur les boucles
    Par membreComplexe12 dans le forum MATLAB
    Réponses: 12
    Dernier message: 05/03/2010, 16h26
  3. Question bete, sur les functions en php
    Par clemsouz dans le forum Langage
    Réponses: 8
    Dernier message: 03/08/2006, 16h10
  4. [Système] question bete sur les pseudo frames
    Par balou dans le forum Langage
    Réponses: 5
    Dernier message: 12/10/2005, 13h11
  5. [Struts] question bete sur les Action et Form
    Par seb_fou dans le forum Struts 1
    Réponses: 2
    Dernier message: 06/09/2004, 15h24

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