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 :

A quoi sert la surcharge de fonction en C++ ?


Sujet :

C++

  1. #1
    Membre éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut A quoi sert la surcharge de fonction en C++ ?
    Bonjour à tous ceux qui passent par là,
    Alors voilà, j'apprend le C++, et une question me vient à l'esprit. J'apprend qu'il est possible de surcharger des fonctions en C++. Sauf que, même en me creusant la tête, je vois pas dans quel cas ça peut servir. Alors voilà, j'viens poser ma petite question ici.
    Merci d'avance à ceux qui répondront
    "C'est d'un ennui…"

    Shikamaru Nara

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Ca te servira le jour où tu auras un cas concret où tu te dis : "tiens ! il me faut la même fonction mais avec des paramètres différents..."

    Exemple avec un constructeur pour créer une couleur ARGB :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Color_ARGB {
    public:
        Color_ARGB();
        Color_ARGB(std::uint8_t red, std::uint8_t green, std::uint8_t blue);
        Color_ARGB(std::uint32_t color);
    private:
        // ...
    };
    Le premier crée une couleur par défaut (du blanc ou du noir), le second prend les 3 composants RGB et utilise une valeur par défaut pour l'alpha, le 3e prend un 32 bits duquel il va extraire 4 composantes. On pourrait en imaginer un 4e avec 4 composantes séparées en 4 std::uint8_t.

    Imagine ensuite que tu as des classes Color_RGB ou encore Color_HSV qui sont d'autres manières de représenter des couleurs.

    Enfin tu as une classe Foo que tu peux colorer. Foo pourrait avoir différentes surcharges de setColor() pour accepter différents formats de couleurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Foo {
    public:
        void setColor(Color_ARGB);
        void setColor(Color_RGB);
        void setColor(Color_HSB);
    };

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Ça sert surtout à ne plus avoir à créer des fonctions processType1, processType2, processType3, ... que tu vois beaucoup en C où la surcharge n'existe pas alors qu'une fonction process qui prend plusieurs types est bien plus logique et simple.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Membre éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut
    Alors déja merci pour vos deux réponses qui sont très clair (et ton exemple est très sympa @Bktero), mais du coup, en quoi un truc équivalent avec des if else ne suffirait pas ? (Je suppose bien que y a une raison ( performance, clarté du code, ou autre), mais je la connais pas donc je demande)
    "C'est d'un ennui…"

    Shikamaru Nara

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Comment tu feras avec des if / else pour mon exemple des constructeurs de ARGB ou les Foo::setColor ?

    "Logique" dans le message de Bousk étant dans le sens de "sémantique" pas et d'"algorithmie". Il ne faut pas voir la surcharge comme résolvant des problèmes d'algorithmie mais comme une façon de simplifier visuellement un code.

    Pour reprendre la classe Foo, ça serait moins élégant d'avoir le code suivant non ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Foo {
    public:
        void setColorUsingARGB(Color_ARGB);
        void setColorUsingRBG(Color_RGB);
        void setColorUsingHSB(Color_HSB);
    };

  6. #6
    Membre éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut
    Moins élégant sûrement, mais dans le fond c'est plus un détail, un p'tit bonus que quelque chose de réellement utile non ? (Question non réthorique)
    "C'est d'un ennui…"

    Shikamaru Nara

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    On peut faire sans, la preuve on fait sans en C. On peut faire avec, la preuve avec tellement d'autres langages. Si c'était un détail inutile, personne ne s'en servirait et les concepteurs de langages ne s’amuseraient pas à en mettre dans les nouveaux langages.

    Imagine des fonctions avec 4 paramètres. Imagine les noms. Pense à la surcharge. Pense à la lisibilité gagnée.

    Après, je te laisse avoir ton avis

  8. #8
    Membre éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut
    Effectivement, ça peut être utile. Après comme je l'ai dit je débute, donc j'ai du mal à imaginer, mais sur un code conséquent, ça peut vite devenir utile j'imagine.
    "C'est d'un ennui…"

    Shikamaru Nara

  9. #9
    Membre éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut
    Dernière question un peu hors sujet. Code::Blocks ou C++ Builder ?
    "C'est d'un ennui…"

    Shikamaru Nara

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Regarde le wiki : Function overloading
    Je tiens à rappeler que c'est la signature qui change mais pas le type de retour. Je ne sais plus comment C++ gère des fonctions qui ont un même nom mais que le type de retour change

    Cela permet de faire un changement dans les traitements : exemple, Print(text_object T) et Print(image_object P).

    Mais c'est surtout très important pour les constructeurs : des constructeurs avec des valeurs par défaut et des constructeurs avec des valeurs fournies en paramètre.

    Les 2 pièges sont "name masking" (à cause de la portée) et "implicit type conversion"
    Effectivement, une fonction peut en cacher une autre parce qu'elle a le même nom et qu'elle est plus proche niveau portée.
    Mais aussi, les conversions implicites font qu'une surcharge avec une portée locale peut tout de même correspondre, alors qu'on veut la surcharge plus globale.
    Un exemple précis, c'est la surcharge d'une méthode F par une classe fille sans masquer celle de la classe mère.

    Le plus gros problème, c'est si le nombre de surcharges est assez important alors on peut ne pas savoir quelle surcharge va être prise à cause des conversions implicites.

  11. #11
    Membre éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut
    Oui ça j'y avais pensé en ayant lu comment ça fonctionner. Faut faire attention quoi. Après je me connais de toute manière, je pense pas l'utiliser, en tout cas pas régulièrement.
    "C'est d'un ennui…"

    Shikamaru Nara

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

    Pour t'aider à comprendre, il faut que tu prenne conscience qu'un projet est quelque chose de "quasi vivant", qui évolue énormément avec le temps

    Mais c'est aussi quelque chose de complexe, dés le départ, qui deviendra de plus en plus complexe au fil du temps. Il existe deux raisons pour lesquelles la complexité augmente:
    1. Parce que les notions que l'on veut décrire au travers du projet sont elles-mêmes complexes; c'est ce que l'on appelle la "complexité intrinsèque" et
    2. parce que l'on décrit des choses "relativement simples" d'une manière "plus complexe que nécessaire". C'est ce que l'on appelle la "complexité induite".


    Or, pour paraphraser Einstien:
    Citation Envoyé par Einstein
    Il faut rendre les choses aussi complexes que nécessaire, mais guère plus.
    On ne sait absolument rien faire contre la complexité intrinsèque, car, il n'y a rien à faire, si tu as besoin d'appliquer la formule E = Mc², tu devras bien fournir "un moyen quelconque" à ton programme pour évaluer M et c.

    Par contre, on peut (on "doit") luter le plus possible contre l'apparition de la complexité induite, qui n'est jamais que la conséquence directe (ou indirecte) des différentes décisions que nous aurons prises.


    Il faut bien comprendre que, pour le compilateur, que tu décides de nommer une fonction setColor, setColorRGB ou ____________ aussi longtemps que ce nom (entre autres choses) permettra au compilateur d'identifier la fonction en question de manière strictement unique et non ambiguë.

    Par contre, pour la personne qui lit le code, le nom est un élément absolument essentiel, car il lui permet de se faire une idée globale de ce qu'est sensé faire le code. Et, bien sur, cette personne aura beaucoup plus facile à se faire cette idée si elle croise l'appel à une fonction nommée setColor ou setColorRGB que si elle croise l'appel à une fonction nommée ... ____________.

    Le problème, c'est que le nom que l'on donne au différentes fonctions (et à tout le reste, d'ailleurs) est -- en lui-même -- une des principales cause de complexité induite parce qu'il n'a réellement du sens que pour le développeur du programme (ou pour celui qui lira le code).

    Car toute chose ne vaut que par l'usage qui en est fait : il n'y a, en effet, aucun intérêt à créer une fonction si c'est pour ... ne jamais y faire appel. Mais plus le nombre de noms à retenir augmente, plus le risque de se rendre compte que le développeur n'a -- tout simplement -- "pas pensé" à utiliser une fonction qui aurait pourtant été "plus efficace" augmente également. Et c'est normal: Si tu dois retenir trois noms de fonctions, tu vas les retenir facilement. Si tu en as dix, tu auras déjà plus facilement tendance à en oublier l'un ou l'autre. Et si tu en as 150 ou 200, combien crois tu que tu vas en oublier

    En outre, imaginons que l'on dispose des fonction setColorRGB, setColorBGRet setColorCMYK. Toutes ces fonctions poursuivent un seul et même objectif : celui de définir la couleur de "quelque chose". La seule différence entre ces trois fonctions, c'est qu'elles utilisent toutes des données de type différent pour atteindre leur objectif (respectivement : une couleur RGB, une couleur BGR et une couleur CMYK). Et comme C++ prend en compte le nombre de paramètre et le type des données transmises comme telles pour identifier de manière unique et non ambigue la fonction qui est appelée que va-t-il, selon toi, se passer si j'essaye d'appeler la fonction setColorRGB en voulant lui transmettre une valeur de type CMYK

    Je te le donne dans le mille : le compilateur s'arrêtera sur une erreur après t'avoir indiqué qu'il ne trouve aucune fonction nommée setColorRGB prenant une couleur CMYK comme paramètre. Ce qui est tout à fait normal.

    La conclusion s'impose d'elle-même : en voulant être "trop précis" au travers du nom donné à nos différentes fonctions, nous avons ajouté "plus de complexité que nécessaire"; autrement dit, de la complexité induite. Cette conclusion est soutenue par deux raisons distinctes:
    1. Le développeur (ou celui qui lit le code) ne s'intéresse qu'au résultat. Il n'en a rien à foutre que le résultat ait été obtenu à l'aide d'une couleur RGB, d'une couleur BGR ou d'une couleur CMYK. Ce qui lui importe, c'est que la couleur a changé (et qu'elle a pris la teinte demandée)!
    2. Le compilateur aurait été tout à fait capable de choisir la "bonne version" d'une fonction nommée setColor en fonction du type de couleur transmis comme paramètre



    De plus, tu te rendras compte lors de ton apprentissage que C++ fournit un tas de possibilités particulièrement étonnantes, parmi lesquelles nous pouvons déjà citer la "généricité" et "l'inférence de types".

    La généricité est une possibilité qui nous est offerte "depuis toujours" de tenir -- pour faire simple -- au compilateur un discours du genre de
    Citation Envoyé par développeur au compilateur
    Je ne sais pas encore exactement quel type de donnée je vais manipuler, mais voici comment elle devra être manipulée
    Ce qui se traduit par un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template <typename T> //Quel que soit le type désigné par T de la donnée manipulé
    void doSomething(T value){ // la fonction doSomething s'attend à recevoir une donnée de type T comme paramètre
        /* on manipule value, qui est de type T pour obtenir le résultat attendu */
    }
    Si toutes les fonctions permettant de définir la couleur s'appelle setColor, avec levée de l'ambiguïté grâce au type de paramètre (autrement dit: des fonctions surchargées), on peut sans aucun problème décider de l'utiliser dans doSomenthing; à condition, bien sur, que T soit, dans le cas présent, considéré comme "l'un des type de donnée représentant les couleurs" (autrement dit : RGB, BGR ou CMYK).

    Avec les fonction setColorRGB, setColorBGRet setColorCMYK, comment pourrais tu savoir quelle fonction tu veux choisir alors que tu n'a aucun moyen de savoir... à quoi correspond T

    L'inférence de type est quant à elle une possibilité "relativement récente" qui n'est apparue qu'en 2011. Cette possibilité nous permet de demander au compilateur de définir lui-même le type d'une donnée comme étant "du type de la donnée renvoyée par une fonction".

    autrement dit, si tu as une fonction Type truc() (le type réel de la donnée renvoyée n'a pas grand importance ici), je peux récupérer la donnée de type T renvoyée par la fonction truc au travers d'un code proche deauto recup = truc(); ce qui impliquera que si truc renvoie une couleur RGB, récup sera une couleur RGB; mais si truc renvoie une couleur BGR, recup sera une couleur BGR; et enfin, que si truc renvoie une couleur CMYK, recup sera ... une couleur CMYK.

    Bien sur, on peut sans doute s'attendre à ce que le développeur qui écrit un tel code aie une idée très précise du genre de couleur renvoyée par truc, même si, en ajoutant la généricité, cette certitude a tendance à disparaitre.

    L'énorme intérêt de cette possibilité, c'est que, si on décide un jour qu'il vaut mieux utiliser la fonction bidule qui renvoie potentiellement une couleur d'un autre type que celui renvoyé par truc, le type de la variable recup s'adaptera de nouveau au type de donnée renvoyé. Si on dispose de fonctions surchargées appelée setColor, l'intérêt de la chose devient alors parfaitement clair, car le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    auto recup=truc(); // mettons que truc renvoie une couleur RGB
    setColor(recup); // ca fonctionne
    et le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    auto recup=bidule(); // mettons que truc renvoie une couleur CMYK
    setColor(recup); // ca fonctionne aussi
    fourniront exactement le même résultat, sans que le développeur n'ait eu à changer autre dans le code que ... la fonction qui lui permettait d'obtenir la couleur à utiliser.

    Avec les fonctions setColorRGB, setColorBGRet setColorCMYK, la "magie" n'aurait pas pu opérer, car, après avoir remplacé l'appel de la fonction truc par l'appel de la fonction bidule, le développeur aurait encore du ... s'assurer de faire appel à la bonne fonction setColorXXX.
    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 éclairé Avatar de viper1094
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2019
    Messages
    570
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2019
    Messages : 570
    Points : 853
    Points
    853
    Par défaut
    Alors déjà un gros merci parce que je pense que ce pavé t'as pris un bon paquet de temps à écrire, ensuite, merci parce que tes exemples me montre des situations ou la surcharge de fonction devient quasi une nécessité ( on peut faire sans mais en passant de 2 lignes de code à 15 donc bon...).
    Et maintenant je connaîtrais les termes "complexité intrisèque" et "complexité induite".
    "C'est d'un ennui…"

    Shikamaru Nara

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

Discussions similaires

  1. A quoi sert un pointeur sur fonction ?
    Par HRS dans le forum C
    Réponses: 2
    Dernier message: 19/03/2014, 18h31
  2. [CognosScript] A quoi sert cette fonction ?
    Par ben_harper dans le forum Cognos
    Réponses: 2
    Dernier message: 23/06/2009, 11h12
  3. Réponses: 0
    Dernier message: 21/10/2008, 15h42
  4. A quoi sert cette fonction
    Par soumia1988 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 10/03/2007, 13h03
  5. A quoi sert la fonction syscall ??
    Par red210 dans le forum Langage
    Réponses: 1
    Dernier message: 29/03/2006, 22h06

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