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

Qt Discussion :

Surcharge des opérateurs


Sujet :

Qt

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de gael21
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2016
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 44
    Par défaut Surcharge des opérateurs
    Bonjour !
    Je bloque depuis 4 jours sur un problème plutôt banal. J'ai écrit une petite base de données pour stocker des données informatiques. Dedans, j'ai une classe "Appareil", en référence avec la table "appareil" de ma BD. Le problème c'est que je voudrai qu'au moment d'un nouvel enregistrement, qu'un teste soit fait avant, histoire de se rassurer que je ne renseigne pas les données qui s'y trouve déjà. Alors je lis ma table et teste les 4 attributs suivants: Marque, Modele, Etat et Prix. Si dans ma base j'ai déjà un enregistrement qui possède les même données que celle que je suis sur le point d'enregistrer, alors je ne modifie que la quantité de ce qui est dans la table.
    J'ai pensé à surcharger l'opérateur "operator+", mais sans succès
    Alors je pensé à faire 2 fonctions:
    une fonction qui lit la BD et teste les données. Si elles sont égales, alors renvoie true. Sinon renvoie false.
    Et une qui modifie la valeur de "quantite"
    Et dans ma fonction "ajouter", je teste la première. si elle est vrai, j'appelle la fonction "modifier...", sinon, j'enregistre mes nouvelles données normalement.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
     
    bool Appareil::teste_donnees(QString a, QString b, QString c, int d)
    {
        //recupérer la valeur contenue dans la base de données
        QSqlQuery request;
        request.exec("SELECT * FROM appareil;");
        while(request.next())
        {
            m_new_id = request.value(0).toInt();
            m_marque = request.value(1).toString();
            m_modele = request.value(2).toString();
            m_etat = request.value(3).toString();
            m_prix = request.value(4).toInt();
            m_new_qte = champ_quantite->value();
            m_new_qte += request.value(6).toInt();
    //voici l'ordre des index dans la table appareil: id, marque, modele, etat, prix, num_serie, quantite, descriptif, apercu
        }
        if(m_marque == a && m_modele == b && m_etat == c && m_prix == d)
            return true;
        else
            return false;
     
    }
     
    void Appareil::modifier_quantite(int new_quantite, int id)
    {
        QSqlQuery request;
        request.prepare("UPDATE appareil SET quantite = :qte WHERE id = :id;");
        request.bindValue(":qte", new_quantite);
        request.bindValue(":id", id);
        request.exec();
     
    }
     
    void Appareil::ajouter()
    {
        //modele_appareil();
     
     
        QString marque_t = champ_marque->text();
        QString modele_t = champ_modele->text();
        QString etat_t = combo_etat->currentText();
        int prix_t = champ_prix->value();
        QString num_serie_t = champ_num_serie->text();
        int quantite_t = champ_quantite->value();
        QString description_t = champ_descriptif->toPlainText();
        QString apercu_t = champ_apercu->text();
     
     
        while(marque_t.isEmpty() || modele_t.isEmpty() || num_serie_t.isEmpty() ||
                description_t.isEmpty())
        {
            QMessageBox::warning(this, "Erreur champ vide", "Veuillez renseigner absolument"
                                                            " tous les champs");
     
            return;
        }
     
        if(teste_donnees(marque_t, modele_t, etat_t, prix_t))
        {
            modifier_quantite(m_new_qte, m_new_id);
        }
        else
        {
     
            QString req = "INSERT INTO appareil (marque, modele, etat, prix, "
                          " num_serie, quantite, descriptif, "
                          "apercu) VALUES(:marque, :modele, :etat, :prix, :num_serie, "
                          ":quantite, :descriptif, :apercu);";
     
            QSqlQuery requete;
            (requete.prepare(req)) ? qDebug()<<"prepare ok" : qDebug()<<requete.lastError().text();
            requete.bindValue(":marque", marque_t);
            requete.bindValue(":modele", modele_t);
            requete.bindValue(":etat", etat_t);
            requete.bindValue(":prix", prix_t);
            requete.bindValue(":num_serie", num_serie_t);
            requete.bindValue(":quantite", quantite_t);
            requete.bindValue(":descriptif", description_t);
            requete.bindValue(":apercu", getNameFile());
            requete.exec();
            clean_champ();
     
            QMessageBox::information(this, "Bravo !", "Les données sur le modèle <strong>" + modele_t + "</strong> ont bien été enregistré dans la"
                                                              " la marque <strong>" + marque_t + "</strong>");
     
        }
    }
    mais quand j'enregistre les données avec les mêmes valeurs, il n'y a pas d'addition sur la quantité. c'est juste un nouvelle enregistrement qui se fait.
    SVP aidez moi. si mon approche(utiliser des banales fonctions) est la bonnes, aidez moi dans ce sens.
    Et si c'est l'utilisation de la surcharge de l'opérateur + qui est meilleure, aidez moi dans ce sens.
    Merci par avance

  2. #2
    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 manière générale, si tu te rends compte que, quelle que soit ta logique, tu ne passe jamais que dans la branche "vrai" (ou dans la branche "faux") d'un test, tu peux raisonnablement penser que... c'est la condition du test en question qui pose problème

    C'est d'autant plus vrai si la condition en question est évaluée par une fonction spécifique, et donc que la logique qui permet de choisir entre les deux branches du tests est complexe au point d'avoir nécessité "tout un algorithme" spécifique pour fournir la réponse

    Ceci étant dit, il faut savoir que les requêtes SQL (surtout celles qui posent des questions) ca entre dans la même veine que les accès fichiers ou les requêtes à des ordinateurs distants : cela permet -- certes -- d'en obtenir énormément d'informations, mais c'est particulièrement lent par rapport à tout ce que l'on pourrait vouloir en faire.

    Du coup, quitte à effectuer une requête (de type "select"), pourquoi n'essayerais tu pas d'en tirer le plus grand parti possible, par exemple, par exemple, en faisant en sorte de maintenir en mémoire l'ensemble des enregistrements qui seront renvoyés par cette requête

    Car, soyons clair : à moins que tu ne te retrouves avec "suffisamment" d'enregistrements que pour que leur maintien en mémoire épuise les ressources de ton ordinateur, tu n'as que des avantages à le faire. Je m'explique:

    Même si cela prend plus longtemps de charger plusieurs dizaines (plusieurs milliers plusieurs millions ) d'enregistrements renvoyés par une seule requête que d'en charger un seul, une fois que ces enregistrements sont chargés, tu n'as plus besoin de "perdre une nouvelle fois du temps" à attendre que ta base de donnée réponde à une question ... à laquelle elle a déjà répondu . C'est le principe de ce que l'on appelle le "cache de données"

    De plus, si tous les enregistrements sont présents en mémoire, cela signifie que tu es en mesure d'accéder "pour ainsi dire directement" (ou, en tout cas, beaucoup plus rapidement que si tu devais passer par la base de donnée) à n'importe quelle information fournie par n'importe quel enregistrement.

    Le seul aspect sur lequel tu perdrais peut-être un peu de temps -- mais, quoi qu'il en soit, toujours moins que si tu passais par la base de données -- serait la sélection, sur base d'un critère donné, de l'enregistrement qui t'intéresse.

    Or, même sur ce point, entre le fait que tu as un champs id (de type int, qui plus est), dont je présumes qu'il fait office de clé primaire dans la table, le simple fait d'utiliser une QMap, dont la clé correspondrait justement à ce champs te permettrait, en utilisant ce champs comme critère de sélection, d'accéder à l'enregistrement ainsi identifié selon une complexité en O(log(N)).

    Penses donc que, même si tu avais plus de quatre milliards (jusqu'à 4 294 967 295, pour être précis) d'enregistrement, une QMap ne devrait en parcourir que maximum ... 32 pour soit te donner l'enregistrement recherché, soit te dire qu'il n'existe pas. Et penses qu'elle ne devrait parcourir que ... 15 enregistrements pour obtenir un résultat similaire si elle en contenait ... 65 535!

    Tu constateras aisément que, bien que ce ne soit pas la solution la plus rapide, c'en est sûrement un concurrent des plus sérieux

    Au pire, tu pourras faire valoir que tu risque aussi de vouloir "trier" les (accéder aux) enregistrement par marque, par modèle ou par état . En fonction des circonstances, une classe issue de boost multiindex pourrait s'avérer particulièrement utile . Et, comme il ne semble pas faire partie des plans de Qt de développer de tels conteneurs, tu serais sans doute bien obligé de te tourner vers ceux de boost Mais bon, ce n'est encore d'un détail.

    Ce qui importe, c'est de se rendre compte de l'énorme intérêt qu'il y a à travailler de la sorte:

    Soit, tu décides de modifier les données d'un enregistrement existant. Et tu t'en rendras très facilement compte avant même que l'utilisateur ne commence introduire les (nouvelles) valeurs, parce que :
    • l'enregistrement dispose d'une valeur pour le champs id
    • tous les autres champs disposent d'une valeur qui leur est propre avant que tu n'essaye de la modifier.

    Si bien que tu peux décider "d'embrayer" sur la partie "mise à jour" de la logique, "simplement" parce que l'enregistrement (à modifier) ... existe.

    Soit tu veux créer un nouvel enregistrement qui n'existe pas encore.
    Et, là encore, tu t'en rendras compte très facilement avant même que l'utilisateur ne commence à introduire les donnée parce que
    • le champs id ne contient aucune valeur
    • d'ailleurs, c'est bien simple: tous les champs sont vide

    si bien que la mise à jour (l'appel à modifier_quantite(m_new_qte, m_new_id); ) pourrait, "tout simplement" se faire à partir d'un slot branché sur le signal editingFinished d'une QLineEdit (par exemple ) que l'insertion pourrait survenir dans le contexte d'une action "plus volontaire" de la part de l'utilisateur, par exemple :
    il y aurait un bouton "add" "quelque part" bien en évidence, sur lequel l'utilisateur devrait cliquer, et qui appellerait un slot qui
    1. afficherait un formulaire permettant à l'utilisateur d'introduire les informations de bas ainsi que les habituels boutons "Ok" et "Annuler"
    2. ne provoquerait l'exécution de la requête insert (et, tant qu'à faire "l'enregistrement en mémoire" du nouvel élément) que si l'utilisateur a choisi le bouton Ok du formulaire en question (à condition, bien sur, qu'il ait correctement rempli le formulaire )

    Cela te permettrait de partir sur deux slots clairement distincts qui n'auraient désormais plus aucune raison de rentrer en conflit

    Le seul problème qui pourrait subsister viendrait de la base de données, et de la capacité qu'elle a (ou non) à gérer ce que l'on appelle "les clés secondaires" basées sur des champs multiples, du moins, d'après la structure de la table qui ressort de ton code.

    Et, à ce sujet, il se fait que la structure de ta table n'est clairement pas la plus efficace qui soit Parce que cette table devrait, à mon sens, être subdivisée quatre tables différentes , de telle manière à ce que les données soient correctement séparées, à savoir:
    1. une table "marque", avec les champs
      • id (clé primaire)
      • marque (chaine de caractères)
    2. une table "designation", avec les champs
      • id (clé primaire)
      • désignation (chaine de caractères)
    3. une table "etat" avec les champs
      • id (clé primaire)
      • chaine de caractères
    4. et enfin, une table "produits" avec les champs
      • id (clé primaire)
      • id_marque (clé externe sur marque.id)
      • id_designation (clé externe sur designation.id)
      • id_etat (clé externe sur etat.id)
      • prix (reel, deux décimal)
      • quantite (entier? reel deux décimales ?)
    En assurant ce que l'on appelle "l'intégrité référentielle", cela te permettrait, non seulement, de créer des requêtes plus "complexes" en fonction de ce que tu veux afficher, mais aussi de t'assurer "plus facilement" que les informations introduites par l'utilisateur lors de l'ajout d'un nouveau produit n'entrent pas en collision avec des produits existants
    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

  3. #3
    Membre confirmé Avatar de gael21
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2016
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 44
    Par défaut
    Bonjour
    Merci Koala01 pour ta réponse.
    Je comprends dans ton message que mon code est loin d'être optimal. Cependant tu ne me donnes aucune piste sur mon problème: tu ne dis pas comment utiliser la surcharge de l'opérateur+, ou l'utilisation des fonctions, afin de vérifier si les nouvelles données existent déjà ou pas.

    Et puis en ce qui concerne la rapidité des mes requêtes, je compte créer un thread (processus) uniquement pour mes requêtes, et une autre pour l'affichage de mes données.
    Mais c'est pas encore le problème. Pour l'heure, j'aimerai juste pouvoir vérifier mes données au moment d'un nouvel enregistrement afin d'éviter d'avoir les doublons, et de mettre à jour mes données si nécessaire.
    Merci par avance

  4. #4
    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
    Citation Envoyé par gael21 Voir le message
    Bonjour
    Merci Koala01 pour ta réponse.
    Je comprends dans ton message que mon code est loin d'être optimal. Cependant tu ne me donnes aucune piste sur mon problème: tu ne dis pas comment utiliser la surcharge de l'opérateur+, ou l'utilisation des fonctions, afin de vérifier si les nouvelles données existent déjà ou pas.
    Tout simplement parce que ton problème actuel, du moins, d'après ce que j'en ai compris, n'a rien à voir avec une quelconque surcharge d'un opérateur.

    Et puis en ce qui concerne la rapidité des mes requêtes, je compte créer un thread (processus) uniquement pour mes requêtes, et une autre pour l'affichage de mes données.
    Qu'il y ait un , deux ou trente-six threads qui tournent sur la machine client ne change absolument rien au problème qui est que
    tu ne peux pas passer ton temps à envoyer des requête à la base de données
    La rapidité avec laquelle tu accéderas aux différentes informations est l'une des raisons essentielles, mais il y en a trente-six autres derrière qui sont déjà toutes prêtes à confirmer ce simple point

    Le simple fait que le temps que ta base de donnée passe à répondre à une requête la place dans l'incapacité de répondre à une autre, qui est peut-être "plus urgente" en est une autre raison.

    Si, vraiment, tu as des requêtes qui doivent être effectuées de manière (très) régulière, au moins en sorte que l'obtention et le traitement du résultat soit le plus bref possible, et donc que le jeu d'enregistrements qui est renvoyé soit "aussi limité que possible"
    Mais c'est pas encore le problème. Pour l'heure, j'aimerai juste pouvoir vérifier mes données au moment d'un nouvel enregistrement afin d'éviter d'avoir les doublons, et de mettre à jour mes données si nécessaire.
    Et ca, c'est justement du domaine de ... la base de données.

    Mais, pour ce faire, il faut impérativement que tes tables soient développées de manière cohérente, avec le respect de l'intégrité référentielle, de manière à ce qu'elle puisse rejeter les requêtes qui auraient pour résultat d'ajouter des doublons.

    Et tout cela n'empêche absolument pas que, avant d'attaquer ta base de donnée, tu puisses mettre en place, au niveau de l'application, une logique qui minimisera le risque d'envoyer des requêtes de ce genre (quitte à ne pas pouvoir garantir qu'elles n’apparaîtront jamais).

    Or, pour arriver à mettre une telle logique en place, il y a une règle à garder en tête en permanence :
    la solution la plus simple est toujours la moins compliquée ... heu, pardon : est toujours la meilleure
    Et il se fait que la solution la plus simple est, comme je te l'ai dit plus haut, de distinguer la situation dans laquelle tu vas -- très clairement -- vouloir modifier un enregistrement existant de celle dans laquelle tu vas (essayer d') ajouter un enregistrement dans la base de données.

    Une fois que tu auras compris cette idée "toute simple" et que tu l'auras mise en oeuvre, tu te rendras compte que le reste... coule pour ainsi dire de source

    Maintenant, si tu tiens à ce qu'on t'explique comment surcharger les opérateur pour une classe ou un type de donnée particulier(e), je peux le faire, mais... cela n'a rien à voir -- à mon sens -- avec ton problème actuel, qui doit être résolu au travers d'une approche totalement différente de celle que tu as utilisée juqu'à présent
    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

Discussions similaires

  1. surcharge des opérateurs
    Par Arson dans le forum C++
    Réponses: 9
    Dernier message: 30/05/2008, 11h40
  2. Réponses: 2
    Dernier message: 11/01/2008, 10h40
  3. Réponses: 7
    Dernier message: 02/12/2007, 21h43
  4. Surcharge des opérateurs ?
    Par kedare dans le forum Ruby
    Réponses: 3
    Dernier message: 06/11/2006, 23h47
  5. Variables polyvalentes et surcharge des opérateurs
    Par Antoine_935 dans le forum C++
    Réponses: 14
    Dernier message: 08/09/2006, 12h38

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