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 :

Template & méthode virtuelle


Sujet :

C++

  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut Template & méthode virtuelle
    Bonjour,

    Actuellement j'essaye de créer une petite bibliothèque permettant d'encapsuler l'accès aux bases de données.

    Mais je me heurte à un problème pour le résultats des requêtes.

    J'ai une classe résultat qui doit avoir une méthode virtuelle pure permettant d'obtenir une ligne de résultat.
    Je pensais donc retourner un tuple et faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename T>
    virtual std::tuple<T> operator[](unsigned int i) = 0;
    Mais on ne peut pas déclarer une méthode template virtuelle :
    erreur : templates may not be 'virtual'

    Que cela ne tienne, il me suffit de créer une classe LigneResultat ainsi qu'une classe ElementResultat et de faire en sorte que Resultat contienne un vector de LigneResultat qui lui-même contienne un vector de ElementResultat.

    Sauf qu'à partir de l'ElementResultat il faut que je puisse le convertir dans le bon type appropriée, conversion qui dépends des bibliothèques d'accès de BDD que j'utilise dans l'implémentation (pqxx pour postgresql, etc...).
    Il faudrait donc que ElementResultat définisse une méthode template abstraite qui serait redéfinie par chaque implémentation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<typename T>
    virtual T as<T>(bool & reussite)= 0;


    Auriez-vous une idée de comment je pourrais procéder?

  2. #2
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 434
    Points : 654
    Points
    654
    Par défaut
    Bonjour tu as une solution ici http://codepad.org/VVjGIDQL

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Bonjour,

    Merci pour ta réponse mais je ne vois pas vraiment comment l'utiliser.

    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
    class Resultat
    {
              template <typename Elements>
              std::tuple<Elements> operator[](int i)
              {
                         //creation du tuple
                         //parcours tuple
                                 Type x = getElements<Type>();
                                 //affectation dans le tuple
                         //fin parcours
              }
     
    }
     
    class PSQLResultat : public Resultat{};
     
    class MySQLResultat : public Resultat{};
    Or je vois mal comment récupérer la valeur dans le bon type (getElement) vu que cela dépend de l'implémentation dans PSQLResultat (implémentation pour postgreSQL, les résultats sont stockés sous forme de pqxx::resultat ) et dans MySQLResultat (implémentation pour MySQL, les résultats sont stockés sous forme de ??? ).

  4. #4
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 434
    Points : 654
    Points
    654
    Par défaut
    Tu ne peux pas la solution est de poser ton interface puis le template via la classe qui implemente ton interface

  5. #5
    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
    Salut neckara,
    De ce que je comprends tu veux mettre dans l'interface ta méthode de traduction des types, or je pense que celle-ci devrait être implementation-defined puisque dépendant du type de db derrière et donc totalement privée.
    Mon attention se porterait plus sur la création d'une interface commune de données, et non sur la factorisation de leur origine et transformation nécessaire pour y arriver.
    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.

  6. #6
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par jouana Voir le message
    Tu ne peux pas la solution est de poser ton interface puis le template via la classe qui implemente ton interface
    Mais comment déclarer la méthode de l'interface vu que selon ce que l'utilisateur demande, peut retourner des types différents.

    Salut neckara,
    De ce que je comprends tu veux mettre dans l'interface ta méthode de traduction des types,
    Non, si c'était le cas, je n'aurais aucun problème avec les "virtuel template", je veux traduire la valeur voulue par l'utilisateur dans le type voulu en utilisant la méthode définie dans l'implémentation. Mais l'utilisateur ne doit pas connaître la classe d'implémentation, il doit passer obligatoirement par l'interface.

    Mon attention se porterait plus sur la création d'une interface commune de données, et non sur la factorisation de leur origine et transformation nécessaire pour y arriver.
    L'interface commune de donnée est la classe Resultat mais il faut réussir à faire une méthode virtuelle pure permettant de récupérer les données que l'utilisateur souhaite et là je bloque totalement.

  7. #7
    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
    Là où je te perds c'est que pour moi Resultat devrait être le plus haut niveau de ta hiérarchie, et peut alors posséder des méthodes template de transformation, non nécessairement virtual.

    Ou alors tu parles de la traduction "user data" => "db data" pour des ajouts en DB ?
    Dans ce dernier cas, il devrait suffire de proposer des méthodes pour les types "normaux" (string, int, ...).
    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.

  8. #8
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    De Resultat héritent PSQLResultat et MySQLResultat.

    Le problème c'est que même en mettant des templates de transformations non-virtuels, ce sont les classes PSQLResultat et MySQLResultat qui savent faire ces transformations, pas Resultat.

    Là je parle de "dbData" => "C++Data"

  9. #9
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2010
    Messages
    434
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2010
    Messages : 434
    Points : 654
    Points
    654
    Par défaut
    Et une interface genre db qui retourne le champ réclamé en paramètre comme en java getString, getInt...

    Et tes obj en dessous tu as un item pour chaque db.
    Après tu manipule l'interface donc tu t'enfou du type de db.

  10. #10
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Et une interface genre db qui retourne le champ réclamé en paramètre comme en java getString, getInt...
    J'y avais pensé mais elle ne me plaisait pas tellement car il faut définir une méthode pour chaque type (long long int, double, char, bool, string) mais je pense que ce doit être la seule solution...

  11. #11
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Ta liste de types est finie, je suppose ? (int, date, string, bool, time, deux trois que j’oublie et basta…).

    Du coup, tu n’as pas besoin de passer par un template. Déclare getAsInt, getAsString, … (parce que de toute façon, je pense que tu vas devoir spécialiser tous tes templates, du coup, l’intérêt me semble limité… Et si ce n’est pas le cas, rien ne t’empêche de déclarer une fonction template privée pour factoriser le bazar).

  12. #12
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Ta liste de types est finie, je suppose ? (int, date, string, bool, time, deux trois que j’oublie et basta…).
    En fait cela risque de dépendre de l'utilisateur et de ce qu'il stocke dans sa base de donnée.
    Je ne peux pas être sûr de faire tous les types nécessaire si par exemple il a stocké un objet en champ de bit dans la base de données (dans ce cas là, un reinterpret_cast<> pourrait être possible (?) ).

    Citation Envoyé par white_tentacle Voir le message
    Du coup, tu n’as pas besoin de passer par un template. Déclare getAsInt, getAsString, … (parce que de toute façon, je pense que tu vas devoir spécialiser tous tes templates, du coup, l’intérêt me semble limité… Et si ce n’est pas le cas, rien ne t’empêche de déclarer une fonction template privée pour factoriser le bazar).
    Même pas, généralement les bibliothèques utilisées on une méthode to<Type> ou as<Type>(T).

  13. #13
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Tu peux peut être remplacer l'héritage par un paramètre template ?

    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
    enum DBType {
    	MySQL,
    	PSQL
    };
     
    template <DBType dbtype>
    struct Element {
     
    	template <class T>
    	struct fail {
    		enum { value = false; }:
    	};
     
    	template <class T>
    	T as(bool& success) {
    		// forcer une spécialisation
    		static_assert(fail<T>::value, "");
    	}
    };
     
    template <> template <>
    int Element<MySQL>::as<int>(bool& success) {
    	...
    }
    Ainsi l'ajout d'un type ne se résume qu'a ajouter une spécialisation pour l'utilisateur. Et avec une spécialisation partielle tu peux avoir une spécialisation pour plusieurs types.

  14. #14
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Tu peux peut être remplacer l'héritage par un paramètre template ?

    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
    enum DBType {
    	MySQL,
    	PSQL
    };
     
    template <DBType dbtype>
    struct Element {
     
    	template <class T>
    	struct fail {
    		enum { value = false; }:
    	};
     
    	template <class T>
    	T as(bool& success) {
    		// forcer une spécialisation
    		static_assert(fail<T>::value, "");
    	}
    };
     
    template <> template <>
    int Element<MySQL>::as<int>(bool& success) {
    	...
    }
    Ainsi l'ajout d'un type ne se résume qu'a ajouter une spécialisation pour l'utilisateur. Et avec une spécialisation partielle tu peux avoir une spécialisation pour plusieurs types.
    Je n'aime pas trop cette solution car l'utilisateur indique le type de base de donnée qu'il souhaite utiliser à l'ouverture de celle-ci ou défini le type de base de donnée par défaut à utiliser.
    Mais ensuite, il ne doit plus y toucher.

    Si je dois faire une classe Element template selon le type de base de donnée, je vais devoir faire de même pour toutes mes autres classes d'accès à la base de données

    L'utilisateur va donc avoir accès en permanence au type de la base de donnée utilisée alors qu'il ne devrait pas, ce qui enlève tout l'intérêt de l'encapsulation de ces bases de données.

  15. #15
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par Neckara Voir le message
    En fait cela risque de dépendre de l'utilisateur et de ce qu'il stocke dans sa base de donnée.
    Je ne peux pas être sûr de faire tous les types nécessaire si par exemple il a stocké un objet en champ de bit dans la base de données (dans ce cas là, un reinterpret_cast<> pourrait être possible (?) ).
    Tu peux prendre en compte les types de bases avec des fonctions non template asInt(), asFloat etc...
    et fournir une méthode unsigned char *asRawData() pour les types utilisateurs, charge à l'utilisateur après de créer l'objet à partir de ça.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Element *elt = /* ... */;
     
    // au lieu d'avoir
    struct UserType { /* ... */ };
    UserType obj(elt->as<UserType>());
     
    // on aurait
    struct UserType {
    	UserType(unsigned char *rawData) { /* ... */ }
    };
    UserType obj(elt->asRawData());
    Bref transférer la logique de la fonction "as" vers les constructeurs des types non pris en charges de base.
    -> le contrôle d'erreurs si le type n'est pas bon est lui aussi divisé en plusieurs endroits, mais les exceptions peuvent résoudre ce problème.

  16. #16
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Si tu as peu d'implémentations, tu peux faire un truc un peu moche et pénible à faire évoluer (impossible d'ajouter une implémentation après coup sans modifier l'interface) :

    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
    class db_impl {
    public :
        virtual ~db_impl() {}
     
        // Toute l'interface qui peut être partagée entre deux implémentations
    }
     
    class db_mysql : public db_impl {
    public :
     
        template<typename T>
        T as (unsigned int i) {
            // Implémentation MySQL
        }
    }
     
    class db_pqxx : public db_impl {
    public :
     
        template<typename T>
        T as (unsigned int i) {
            // Implémentation pqxx
        }
    }
     
    // ...
     
    enum db_type {
        mysql,
        pqxx,
        // ...
    };
     
    class db {
        std::unique_ptr<db_impl> impl;
        db_type type;
     
    public :
     
        template<typename T>
        T as(unsigned int i) {
            switch (type) {
            case mysql : return dynamic_cast<db_mysql&>(*impl).as<T>(i);
            case pqxx  : return dynamic_cast<db_pqxx&>(*impl).as<T>(i);
            // ...
            }
        }
    };
    Un autre inconvénient est que l'appel à db.as<T>(i) doit compiler pour toutes les implémentations possibles, quelle que soit celle qui est effectivement utilisée.

  17. #17
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Bonjour,

    Merci pour vos réponses.
    Je pense utiliser la solution de Iradrille reprenant celle de white_tentacle et de jouana qui me semble être le plus intéressant.

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 26/10/2010, 11h33
  2. méthodes virtuelles
    Par ep31 dans le forum C++
    Réponses: 2
    Dernier message: 09/11/2005, 17h21
  3. classe Template et méthodes "générales"
    Par rulianf dans le forum Langage
    Réponses: 1
    Dernier message: 26/10/2005, 13h42
  4. Comment l'appel à une méthode virtuelle....
    Par Blobette dans le forum C++
    Réponses: 7
    Dernier message: 07/12/2004, 13h55
  5. [C#] Méthode virtuelle
    Par jacma dans le forum Windows Forms
    Réponses: 4
    Dernier message: 07/11/2004, 08h18

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