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 :

Souci avec une surcharge polymorphe d'opérateur


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Points : 17
    Points
    17
    Par défaut Souci avec une surcharge polymorphe d'opérateur
    Bonjour,

    J'ai surchargé, dans une de mes classes, l'opérateur <<, afin d'ajouter plus facilement des paramètres de divers types (une classe préparant une requête SQL, et convertissant au passage, selon leur type, les paramètres fournis, pour qu'ils soient au format attendu).

    Par exemple, une chaîne devrait être simplement concaténée, une date sera convertie en une chaîne d'un format acceptable pour la base, puis concaténée, un booléen devrait être traduit en FALSE ou TRUE, un tableau binaire pourra être "escapé" avant d'être ajouté, etc.


    La plupart de ces opérateurs fonctionnent très bien, et me donnent les résultats escomptés. Cependant, T& T::operator<<(bool b) ne marche pas. En effet, bien que l'opérateur soit présent, il semblerait que le compilateur préfère faire une conversion implicite de mon booléen en int, puis passer par mon T& T::operator<<(int i). J'ai donc des affichages, dans ma requete, de "0" au lieu de "FALSE", par exemple, ce qui est assez gênant.

    Quelqu'un aurait-il une idée de ce qui pourrait causer ce comportement ? Y'a-t'il un moyen de désactiver les conversions explicites, au moins dans ce contexte ? Ou, sinon, y'a-t'il moyen de le forcer à utiliser cette forme de la méthode, plutôt qu'une autre, de manière "simple" ?

    Parce que le but est tout de même d'écrire T << mon_bool, pas T.operator<<(mon_bool)


    Merci par avance

  2. #2
    Membre habitué

    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2008
    Messages
    39
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

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

    Informations forums :
    Inscription : Février 2008
    Messages : 39
    Points : 169
    Points
    169
    Par défaut
    Salut,

    D'abord, je voudrais savoir si tu es sûr que ton programme passe effectivement par la fonction qui prend (int i) en argument. En effet, selon la concaténation que tu fais dans la fonction qui prend (bool i) en argument, tu pourrais très bien te retrouver avec 0 ou 1 dans ta chaine, puisque ces valeurs numériques correspondent à true et false.

    Maintenant, si effectivement il y a une conversion implicite, tu peux peut-être passer outre en mettant en place une conversion explicite du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    T << mon_bool, pas T.operator<<((bool)mon_bool)
    Bonne journée,

    Aldiemus

  3. #3
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Est-ce que ça ne passe pas par une fonction/méthode template avant l'appel à l'opérateur de sérialisation ?

    MAT.

  4. #4
    Membre habitué Avatar de nowahn
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 84
    Points : 150
    Points
    150
    Par défaut
    Bonjour,

    La première remarque de Aldiemus est très pertinente, commence par bien cerner l’opérateur qui est appelé (genre en mettant un std::cout << qqchose dans celui que tu t’attends à ce qu’il soit appelé).
    Ensuite, dans quel contexte est appelé cet opérateur ?
    Dans ce cas-ci :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bool B=true;
    T << B;
    L’opérateur pour les bool devrait clairement être appelé.
    Mais dans le cas suivant :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    T << FonctionQuiDevraitRetournerUnBool();
    Il y a des fonction qu’on utilise comme si elle renvoyaient un bool, mais qui renvoient un int (c’est le cas de beaucoup de fonction de la bibliothèque C).
    Quel est le contexte de ton appel de cet opérateur ?
    As-tu essayé avec un appel aussi clair que le premier cas que je donne ?

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Points : 17
    Points
    17
    Par défaut
    Nowahn : Oui, c'est bien le premier cas que j'utilise.

    Pour les autres, je manque de temps pour répondre en ce moment, mais je reviens poster ici dès que j'aurai eu le temps de me repencher sur le problème.

  6. #6
    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,
    Il va nous falloir un peu plus de détail et de code. Car un exemple trivial fonctionne :
    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
    #include <iostream>
     
    struct dummy
    {
    };
     
    dummy& operator<<(dummy &d_, int i_)
    {
        std::cout<<"dummy& operator<<(dummy d_, int i_)\n";
     
        return d_;
    }
     
    dummy& operator<<(dummy &d_, bool b_)
    {
        std::cout<<"dummy& operator<<(dummy d_, bool b_)\n";
     
        return d_;
    }
     
    int main()
    {
        dummy d;
        int i(1);
        bool b(false);
        d<<i;
        d<<b;
        d<<(i==1);
    }
    Produit :
    dummy& operator<<(dummy d_, int i_)
    dummy& operator<<(dummy d_, bool b_)
    dummy& operator<<(dummy d_, bool b_)

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Points : 17
    Points
    17
    Par défaut
    Bon, mea culpa. Il y avait bien un souci de booléens, mais qui ne correspondait pas à ma description du problème (qui avait dû être faite de mémoire).

    En fait, nous avons eu des soucis avec la conversion de chaînes, ce qui causait nos problèmes. J'explique : Nous utilisons Qt, qui définit une classe QString (pour laquelle existe un constructeur implicite à partir de const char *). Nous avons donc l'habitude de fournir, en argument, là où un QString est attendu, une chaîne constante C quand cela s'avère plus pratique. Il faut dire qu'un x.append("toto"), c'est plus lisible que x.append(QString("toto")).

    En bref, nous avions une classe avec moult operator<<(), pour moult types différents. Entre autre, les int, les booléens, les QString, etc. Mais nous n'avions pas surchargé pour les char *.

    Au final, quand on passait une chaine constante, au lieu qu'il applique la conversion implicite en QString (à laquelle nous nous étions habitués), il avait tendance à favoriser la conversion de ce pointeur... en booléen. Donc, nous passions la chaîne "FALSE", qui était donc un pointeur sur caractère non nul, et nous nous attendions à voir "FALSE" s'ajouter à la requête SQL qu'on créait. Oui, sauf que le compilateur, voyant plusieurs conversions implicites, a plutôt décidé, tout seul, dans son coin, qu'un pointeur non-nul, c'était une expression boléenne VRAIE, puisque un "entier différent de 0", en gros. Donc, il utilisait l'operator<<(bool) à la place de l'operator<<(QString) que nous nous attendions à utiliser.

    Résultat, affichage de TRUE au lieu de FALSE (et arrachage de cheveux), evidemment.

    Quand j'ai compris ça, j'ai ajouté un operator<<(const char *), et depuis, ça marche sans problème.



    Donc, une question un peu plus intéressante se pose désormais : Où peut-on trouver (ou comment peut-on déterminer autrement que par essais et erreurs) les priorités de conversion implicite ? Et est-il possible de les désactiver, ou de les forcer dans un ordre précis (du style, les conversions "maison", PUIS les conversions "par défaut") ?

    Merci par avance pour vos réponses, et désolé, une fois encore, pour le temps que je vous ai fait perdre avec ma description erronée du problème. Je me fais seppuku et je reviens

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

    De manière générale, le compilateur prend le chemin le plus court qui s'offre à lui.

    Il choisira, en priorité, le "match parfait", s'il existe (en utilisant un int, par exemple, s'il y a une fonction qui en attend un), puis les éventuelles promotions (en promouvant un char en int, par exemple).

    S'il n'y a pas de match parfait ou nécessitant une promotion, il va se tourner
    1. vers les classes pour lesquelles il existe un constructeur implicite pouvant servir d'opérateur de conversion, c'est à dire:
      • n'étant pas qualifié explicit
      • prenant un et un seul paramètre, passé par valeur ou par référence constante
    2. OU vers les classes proposant un opérateur de conversion implicite vers l'un des types qui font le match parfait.
    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

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

Discussions similaires

  1. [WD9] [Débutant] Souci avec une simple requête
    Par unix27 dans le forum WinDev
    Réponses: 4
    Dernier message: 04/04/2006, 00h54
  2. souci avec une comparaison de date
    Par Ludo75 dans le forum SQL Procédural
    Réponses: 6
    Dernier message: 20/02/2006, 15h59
  3. [MySQL] Soucis avec une insertion dans une base
    Par Ludo75 dans le forum PHP & Base de données
    Réponses: 13
    Dernier message: 27/01/2006, 14h03
  4. [Custom Tags] Problème avec une surcharge de méthode
    Par Strab dans le forum Taglibs
    Réponses: 19
    Dernier message: 26/08/2005, 16h34
  5. SOucis avec une reequete imbriquee
    Par Ni4k dans le forum Langage SQL
    Réponses: 6
    Dernier message: 30/03/2004, 08h56

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