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 :

[Debutant] Regles surcharge fonctions


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2007
    Messages
    257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2007
    Messages : 257
    Par défaut [Debutant] Regles surcharge fonctions
    Bonsoir,
    J'aimerais savoir si quelqu'un pourrait m'eclairer au niveau de la surcharge de fonctions, à savoir est ce qu'il existe un tutoriel à ce sujet pour savoir quelle fonction sera appelée parmis plusieurs sosies.
    Peut etre quelqu'un aurait des methodes sur ce domaine à faire partager.
    Merci

  2. #2
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 38

  3. #3
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Ouais mais justement :
    D'une manière générale, le compilateur dispose d'un ensemble de règles (dont la présentation dépasse le cadre de ce livre)

    Je viens de faire tout un speech à ce sujet ici : http://www.developpez.net/forums/sho...d.php?t=474036

    C'est pas non plus exaustif.
    Par example il faut savoir que pour résoudre une ambiguité, si le compilateur à le choix entre une fonction template et non template, il choisira la non template.
    De même entre deux fonctions template, le compilateur choisira la plus spécialisée (pas toujours possible à déterminer) donc la question devient : qu'est ce qui fait qu'une fonction template est plus spécialisée qu'une autre?

    Mais déjà ça peut te donner une idée.

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Il y a très peu de gens au monde qui connaissent et maîtrisent toutes les subtilités de la résolution de surcharge de fonctions en C++. Peut-être quelques écrivains de compilateurs, s'ils ont fait ça il y a peu de temps...

    La règle principale à retenir, c'est que dans la grande majorité des cas, ça marche de manière "naturelle" pour l'utilisateur...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    La règle principale à retenir, c'est que dans la grande majorité des cas, ça marche de manière "naturelle" pour l'utilisateur...
    C'est très vrai. Le seul moment où ça peut vraiment déconner, c'est lorsque le programmeur a lui même implémenté des opérateurs de convertions implicites à foison dans ses classes. Là on peut se trouver face à des bizareries.

    On peut noter aussi que le compilateur tente d'enchaîner plusieurs convertions implicites à la suite (cast d'un pointeur vers un objet -> void* puis -> bool) mais il n'utilisera au maximum qu'un seul opérateur de convertion implicite définit par l'utilisateur dans sa séquence.

  6. #6
    Membre expérimenté
    Profil pro
    Dev
    Inscrit en
    Décembre 2007
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Décembre 2007
    Messages : 191
    Par défaut
    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
    #include <iostream>
    using namespace std;
     
    void maFonc(int a) {cout << "Fonction int appelée" << endl;}
    void maFonc(long a) {cout << "Fonction long appelée" << endl;}
    void maFonc(float a) {cout << "Fonction double appelée" << endl;}
     
    int main() {
        int x = 0;
        long y = 0;
        float z = 0;
        double probleme = 0;
     
        maFonc(x);  // pas d'ambiguité, le type du param joue parfaitement
        maFonc(y);  // pas d'ambiguité
        maFonc(z);  // pas d'ambiguité
     
        maFonc(5);  // compile parfaitement car 5 est un constante entiere, int par defaut. Ce'st bien maFonc(int) appelée. 
        // S'il n'y a PAS de maFonc(int), erreur car 5 peut etre converti en float ou en long de manière équivalente pour le compilo. 
        //(il y aurait conversion implicite, mais il ne sais pas en quoi le faire car il connait plusieurs manière de le faire)
     
        maFonc(0.25); // 0.25 est une constante double. 
        //Elle peut facilement etre convertie en float, mais aussi int ou long du point de vue du compilo,
        // encore une fois ce sont des conversions implicites qui devraient avoir lieu, mais le compilo ne sait pas laquelle ... 
        //Donc erreur de compilation (resolution ambigüe).
     
        maFonc( static_cast<float>( 0.25 )); // compile. pas d'ambiguité, on donne explicitement la conversion à faire.
     
        maFonc(probleme); //ne compile pas pour les memes raisons que 0.25 
    }

    je ne sais pas s'il existe des compilos mais ce bout de code devrait t'éclairer un peu.

    En fait tout est un histoire de conversion implicite :

    Si le type de la variable (ou constante) joue parfaitement avec une des fonctions surchargées, c'est celle là qui sera prise.

    Si non le compilo regarde s'il sais faire des conversions de type. Par exemple un compilo sais faire une conversion d'une classe fille vers une classe mère lors d'héritage (en cas d'héritages multiples). de plus les divers constructeurs d'objets fournissent en fait des opérations de conversions.

    Et donc : si le compilo remarque qu'il peut convertir de plusieurs manières l'argument de sorte qu'il joue avec *plusieurs* fonctions surchargées -> Erreur de compilation (résolution de conversion ambigue). Sinon c'est bon, il convertit l'argument de la seule manière utilisable par une seule fonction surchargée.

  7. #7
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par Pacorabanix Voir le message
    maFonc(5);
    // S'il n'y a PAS de maFonc(int), erreur car 5 peut etre converti en float ou en long de manière équivalente pour le compilo.
    //(il y aurait conversion implicite, mais il ne sais pas en quoi le faire car il connait plusieurs manière de le faire)
    Et bien normalement non car int -> long est une simple promotion et int -> float requiert une convertion standard.

    maFonc(0.25); // 0.25 est une constante double.
    //Elle peut facilement etre convertie en float, mais aussi int ou long du point de vue du compilo,
    // encore une fois ce sont des conversions implicites qui devraient avoir lieu, mais le compilo ne sait pas laquelle ...
    //Donc erreur de compilation (resolution ambigüe).
    Ici oui car il s'agit de double -> float. Ce serait l'inverse, il pourrait de la même manière faire une promotion.

    En fait tout est un histoire de conversion implicite :
    Pas uniquement. Dans l'idée je suis d'accord mais il y a des subtilités (voir mon autre post).

    Si le type de la variable (ou constante) joue parfaitement avec une des fonctions surchargées, c'est celle là qui sera prise.
    Exact.

    de plus les divers constructeurs d'objets fournissent en fait des opérations de conversions.
    C'est aussi à prendre en compte oui.

  8. #8
    Membre expérimenté
    Profil pro
    Dev
    Inscrit en
    Décembre 2007
    Messages
    191
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dev

    Informations forums :
    Inscription : Décembre 2007
    Messages : 191
    Par défaut
    Citation:
    Envoyé par Pacorabanix Voir le message
    maFonc(5);
    // S'il n'y a PAS de maFonc(int), erreur car 5 peut etre converti en float ou en long de manière équivalente pour le compilo.
    //(il y aurait conversion implicite, mais il ne sais pas en quoi le faire car il connait plusieurs manière de le faire)
    Et bien normalement non car int -> long est une simple promotion et int -> float requiert une convertion standard.
    J'ai testé (je ocmpile sous XCode), une erreur se passe bel et bien. Apparemment la promotion int -> float et int -> long est au meme niveau pour le compilo.



    Pour compléter ce qui a été dit ici, l'exemple de la FAQ permet aussi de cerner une subtilité (tout a fait naturelle je trouve) lorsqu'il y a plusieurs arguments.

    Ce code :
    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
     
    #include <iostream>
    using namespace std;
     
    void test(int i, int j)
    {
        cout << "test(int, int)" << endl;
    }
     
    void test(float i, float j)
    {
        cout << "test(float, float)" << endl;
    }
     
    int main() {
        int x = 0;
        float z = 0;
     
        test(x, x); // utilise int, int
    	test(z, z); // utilise float, float
     
        test(2, 2.5); // utilise int, int (warning car convertit 2.5 (double) en int)
    	test(2.5, 2); // utilise int, int (warning car convertit 2.5 (double) en int)
    	// car un des arguments joue DEJA PARFAITEMENT ( le int),
    	// reste a convertir le double en ... int! (seule possibilite)
     
    	test( z, x); // error un float un int, il ne sait aps dans quel sens la convertion doit se faire	
    	test(x, z); // error idem
     
    	test(2.5, 2.5); // error
     
    }
    genère chez moi ces erreurs :

    gcc
    /Users/lioobayoyo/test/main.cpp: In function `int main()':
    /Users/lioobayoyo/test/main.cpp:21: warning: passing 'double' for converting 2 of 'void test(int, int)'
    /Users/lioobayoyo/test/main.cpp:22: warning: passing 'double' for converting 1 of 'void test(int, int)'
    /Users/lioobayoyo/test/main.cpp:26: error: call of overloaded 'test(float&, int&)' is ambiguous
    /Users/lioobayoyo/test/main.cpp:4: note: candidates are: void test(int, int)
    /Users/lioobayoyo/test/main.cpp:9: note: void test(float, float)
    /Users/lioobayoyo/test/main.cpp:27: error: call of overloaded 'test(int&, float&)' is ambiguous
    /Users/lioobayoyo/test/main.cpp:4: note: candidates are: void test(int, int)
    /Users/lioobayoyo/test/main.cpp:9: note: void test(float, float)
    /Users/lioobayoyo/test/main.cpp:29: error: call of overloaded 'test(double, double)' is ambiguous
    /Users/lioobayoyo/test/main.cpp:4: note: candidates are: void test(int, int)
    /Users/lioobayoyo/test/main.cpp:9: note: void test(float, float)
    et les fonctions qu'il utilise sont indiquées en commentaires.

    Pour test(int, double) -> test (int, int) et test(double, int) -> test(int, int)

    Cela me semble normal : si des arguments jouent *deja* parfaitement sans conversion, le compilo va d'abord voir s'il peut convertir les arguments qui ne jouent pas. Et seulement après il tentera de convertir des arguments qui jouaient pourtant deja bien avec certaines versions surchargées.

    EDIT:Cela clarifie pas mal l'ordre de décision deja . après c'est vrai qu'il y a toujours les cas super tordus. Mais dans ce cas chaque cas nécessiterai un post à lui je pense .

  9. #9
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par Pacorabanix Voir le message
    J'ai testé (je ocmpile sous XCode), une erreur se passe bel et bien. Apparemment la promotion int -> float et int -> long est au meme niveau pour le compilo.
    Effectivement il n'y a pas de promotion de int -> long, j'aurai cru.

    Par contre il y en a bien dans chacun des exemples :
    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
    void func( int );
    void func( long );
    void func( double );
     
    int main()
    {
      char  c = 5;
      short s = 5;
      bool  b = true;
      float f = 5;
      func( c );
      func( s );
      func( b );
      func( f );
    }

  10. #10
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Janvier 2008
    Messages : 38
    Par défaut
    Bonsoir
    http://cpp.developpez.com/cours/cpp/...age_3#LIII-F-4
    Ouais mais justement :
    D'une manière générale, le compilateur dispose d'un ensemble de règles (dont la présentation dépasse le cadre de ce livre)
    comment le compilateur sait quelle version de la fonction func() il faut appeler ?

    il collecte toute les fonctions accessible de la symbole-table qui ont le même nom que la fonction func
    exclue toute les fonction qui n'ont pas le même nombre de paramètres
    si aucune fonction ne correspond alors il renvoie une erreur
    le compilateur choisit directement une fonction si les les arguments sont exactement les paramètres.

    Si il ya plus d'une correspondance, choisir la meilleure correspondance.
    Lors de la décision sur la meilleure correspondance, le compilateur fonctionne sur un système de notation selon l'ordre suivant :
    1. Une correspondance exacte
    2. Une promotion
    3. Une conversion standard
    4. un constructeur ou une conversion définie par l'utilisateur

    >une promotion c-a-d un des cas suivant :
    *{char, unsigned char, short} -> int
    *float->double
    *bool-> int

    >ou une conversion standard de type c-a-d:
    * conversions entre types scalaire, à l'exception de ceux qui sont considérés comme des promotions.
    * Conversions entre les types flottant: double, float et long double
    * Conversions entre les types flottants et scalaire
    * conversions de scalaire, pointeur et de type flottant à bool (zéro ou NULL est FALSE, tout le reste est VRAI)
    * Conversion d'un entier à zéro le pointeur NULL.

    >S'il n'y a pas de gagnant clair des meilleurs correspondance, le compilateur signale une erreur


    un lien en anglais http://www.dcs.bbk.ac.uk/~roger/cpp/week20.htm

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par poukill Voir le message
    Attention, convertir 5 de int en float fait aussi perdre des données, car le résultat va certainement donner quelquechose comme ça :
    5.000000007 Ceci est dû au codage interne des nombres flottants !
    Citation Envoyé par JolyLoic Voir le message
    Sauf erreur de ma part (ce n'es pas mon domaine, donc risque d'erreurs), une telle erreur ne peut pas arrive, un nombre entier petit étant représentable de manière exacte.
    Je ne connais pas de formats de flottants ou les entiers suffisamment petits ne soient pas représentables et même si ça ne garanti pas que la conversion de l'entier 5 en flottant donne le flottant 5.0, il y a bien peu de risques d'avoir une implémentation d'aussi faible qualité.

    A noter, dans la plupart des formats de flottants, la plupart des fractions decimales ne sont pas representables. Donc 1.1 n'est pas representable et on a donc bien une valeur legerement plus petite ou plus grande. De meme pour 0.1. Et il y a peu de chances que ces arrondis se compensent pour que la soustraction du resultat des deux conversions fasse exactement 1.0.

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

    De fait, quand un int est converti en double (ou en float) on peut effectivement se trouver face à une différence, mais, tout bien mesuré, la différence ne pourra jamais excéder le delta du type réel pour la conversion

    On peut donc parfaitement envisager un 1 (int) qui, converti en float, vaille 0.000000009 ou, au contraire, qui vaille 1.000000001, mais ce sera le plus souvent parce que c'est le delta pour les float, et le raisonnement peut etre suivi à l'identique pour les double

    Et c'est d'ailleurs exactement le raisonnement qui fait que les (bons) compilateurs (bien réglés) nous signalent qu'une égalité entre deux réels est toujours fausse, du fait de ce fameux delta (que l'on peut utiliser en incluant <limits> )
    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

  13. #13
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Sur mon message plus haut, j'avais donné le lien vers la FAQ qui en parlait !

  14. #14
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par koala01 Voir le message
    On peut donc parfaitement envisager un 1 (int) qui, converti en float, vaille 0.000000009 ou, au contraire, qui vaille 1.000000001
    Je n'envisage pas. C'est formellement conforme mais je n'envisage pas qu'une implementation aussi bizarre puisse se retrouver sur le marche.

    Et c'est d'ailleurs exactement le raisonnement qui fait que les (bons) compilateurs (bien réglés) nous signalent qu'une égalité entre deux réels est toujours fausse,
    L'egalite entre reel a toujours un sens. L'egalite entre flottants est plus delicate a maitriser -- en particulier si on veut savoir quand on peut tester l'egalite entre deux resultats de calcul -- mais il y a des cas ou elle a un sens.

    Les flottants sont perturbants parce que
    1/ des nombres apparemment simples ne sont pas representables
    2/ des nombres apparemment simples ne sont pas representables
    3/ ce ne sont pas des reels

    Apparemment la plupart des gens ne vont pas plus loin que de remarquer que les resultats leur semble etranges pour ces deux raisons et en concluent que l'utilisation de flottants introduits des imprecisions de maniere impredictibles. La constation est correcte -- l'utilisation de flottants donne des resultats etranges quand on n'a pas compris les consequences de ces deux points -- mais la conclusion est fausse -- les flottants sont maitrisables et quand on le fait on peut avoir des resultats d'une precision predictible.

  15. #15
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Ne voulais-tu pas dire 0.999999999 ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  16. #16
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ne voulais-tu pas dire 0.999999999 ?
    Si bien sur... Mais bon, on avait compris !
    C'est comme Jean-Marc qui a mis 3 points au lieux de deux...

    En tout cas, je suis d'accord. Il existe une discipline entière pour ça qui s'intitule "calcul scientifique" et il est bon de connaitre comment sont représentés les flottants en mémoire (mantisse, exposant) et les dangers de divergence d'un algorithme avec un problème mal posé / matrice mal conditionnée...

Discussions similaires

  1. Réponses: 11
    Dernier message: 03/04/2007, 13h34
  2. [Debutant]Les surcharges ne m'aiment pas ( << et >&
    Par Geolem dans le forum Débuter
    Réponses: 2
    Dernier message: 06/12/2005, 20h34
  3. [debutant]Chaine et fonction
    Par Halobox dans le forum C
    Réponses: 9
    Dernier message: 20/11/2005, 00h39
  4. [debutant]appeller une fonction d'une classe fille et mere ?
    Par Battosaiii dans le forum Débuter
    Réponses: 1
    Dernier message: 12/11/2005, 12h56
  5. Réponses: 9
    Dernier message: 22/07/2005, 16h10

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