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 :

Pb de Template


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut Pb de Template
    Bonjour,
    pour rendre générique une classe, j'aimerais utiliser un 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
     
    class CMaillon
    {
    private :
     char* info;
     CMaillon* suiv;
     
    public:
    CMaillon(char* x, CMaillon* s) {
      info = new char[strlen(x) + 1];
      strcpy(info, x);
      suiv = s;
     
    ~CMaillon() {
     delete info;
    }
    }
    Donc j'aimerais que cette classe soit utilisable pour n'importe quel objet.

    Je voulais faire qqchose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template< typename T>
    class CMaillon
    {
    ...
    CMaillon(T x, CMaillon* s);
    }
    Mais du coup, comment vais-je faire mon allocation de la variable info en utilisant un template ?

    Merci par avance.
    @+

  2. #2
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    En instanciant ta variable info de type T ... ?
    Soit :
    info = new T(args du constructeur);
    soit dans la liste d'initialisation, avec info(args du constructeur) ...

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T>
    class CMaillon
    {
    private :
     T info;
     CMaillon* suiv;
     
    public:
    CMaillon(const T& x, CMaillon* s) : info(x), suiv(s){
    }
    };
    Ce qui met en évidence le manque d'intérêt de ton code.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 636
    Par défaut
    Salut,

    Quand tu utilises les modeles (je trouve ce terme plus "francais" que celui de template ), le principe reste toujours le meme:

    il faut que tu fournisse un type générique, et que tu l'utilises partout où tu veux la généricité.

    Cela signifie que, si tu définis ta classe sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    typedef <typename T>
    MaClasse
    {
        MaClasse()
       (...)
       T Donnee
       (...)
       Fonction(T *intro)
    };
    Il faudra indiquer pour chaque bloc de déclaration/implémentation qu'il doit utiliser le type générique.

    Autrement dit, pour la déclaration, le template <typename T> s'applique dans l'ensemble de la déclaration de ta classe,et ca passera si tu décides d'implémenter les méthodes directement dedans sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template <typename T>
    class MaClasse
    {
        MaClasse(T&)
            {
                //implémentation du constructeur
            }
    };
    Si tu décide de déporter l'implémentation (dés qu'elle sort du bloc déclarant la classe, il faudra le faire sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template <typename T>
    Maclass<T>::Fonction(T *intro )
    {
        //implémentation de la méthode
    }
    L'héritage pourrait se faire de deux manières
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    // la classe dérivée est, elle aussi, une classe modèle
    template <typename T>
    class Derivee: public MaClasse<T>
    {
       ...
    };
    // ou la classe hérite d'un modèle dont le type est connu
    classe Derivee:public MaClasse<int>
    {
     
    };
    et que, enfin, l'instanciation se fasse en indiquant le type à utiliser sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MaClasse *objet=new MaClasse<le type souhaité>(les arguments éventuels);
    Pour l'instanciation, si la synthaxe MaClasse<Type à utiliser> te parrait réellement trop complexe, ce qui peut arriver, par exemple, lorsque tu as plusieurs type à préciser, et que certains sont, eux-memeq, des modèles, ou, tout simplement, parce que tu prévois de travailler souvent avec ta classe modèle utilisant un type précis, il est peut etre intéressant de déclarer un nouveau type sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef MaClasse<int> MaClasseInt;
    (le débat fait rage, mais il vaut mieux utiliser typedef que l'instruction préproc #define ) et de travailler alors avect MaClasseInt.

    J'ai sciemment pris certains raccourcis et laissé quelques imprécisions sur le coté parce que le post devenait déjà grand... le principal étant AMHA que tu puisse comprendre "en gros" l'utilisation de tes templates
    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

  5. #5
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    MaClasse *objet=new MaClasse<le type souhaité>(les arguments éventuels);
    C'est quoi cette idée tordue d'instancier des classes avec new ?

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 636
    Par défaut
    Citation Envoyé par loufoque
    C'est quoi cette idée tordue d'instancier des classes avec new ?
    Et pourquoi pas, d'abord???

    Si, pour une raison ou un autre, tu as besoin de gérer cet objet de manière dynamique, c'est une manière de faire qui en vaut une autre...

    D'autant plus que, quand on voit la classe présentée en exemple dans la question de olive_le_malin, il s'agit clairement d'une liste ou d'une file, et que, dans ce genre de cas, tu n'as pas beaucoup d'autre solutions pour la gérer (si tu décide de ne pas utiliser la STL, du moins)...

    Edit==>Au fait, mais, tu ne l'a peut etre pas remarqué parce que, effctivement j'ai fait une petite erreur dans le code qui devrait etre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClasse<le type souhaité> *objet=new MaClasse<le type souhaité>(les arguments éventuels);
    mais j'utilise ici un pointeur, et, jusqu'à preuve du contraire, instancier dynamiquement un pointeur sur un objet, ca se fait avec new
    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

  7. #7
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Naturellement, la question de fond c'est pourquoi ne pas utiliser std::string qui est le type des chaînes de caractères en C++ ou std::vector qui est le type des tableaux? En poussant plus loin, pourquoi ne pas utiliser simplement std::list plutôt que d'inventer un type de liste de plus?

    Et utiliser std::string aurait vraissemblablement évité le problème de chercher comment allouer info dans la version template: tu n'aurais pas eu l'idée de faire de l'allocation dynamique pour un std::string employé comme cela.

    Quelques remarques supplémentaires:

    Tu fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    info = new char[strlen(x) + 1];
    ...
    delete info;
    Pour libérer quelque chose qui a été alloué avec new[], il faut utiliser delete[], doncTu laisses le constructeur par copie et l'opérateur d'assignement à leur version définie par le compilateur alors que le destructeur fait quelque chose, c'est mauvais signe et effectivement tu risques de libérer deux fois de la
    mémoire et d'avoir des fuites.

    C'est généralement pas une très bonne idée de passer par valeur des arguments dont le type est déterminé par un paramètre template, une référence constante va éviter des copies potentiellement coûteuses.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Bonjour,
    Merci à vous tous, notamment Koala01 pour tes explications générales sur les "Modèles"

    Jeans-Marc.Bourguet :

    --> pour le delete je pensais que [] était utilisé si on libérait un tableau alloué.

    Naturellement, la question de fond c'est pourquoi ne pas utiliser std::string qui est le type des chaînes de caractères en C++ ou std::vector qui est le type des tableaux? En poussant plus loin, pourquoi ne pas utiliser simplement std::list plutôt que d'inventer un type de liste de plus?

    Et utiliser std::string aurait vraissemblablement évité le problème de chercher comment allouer info dans la version template: tu n'aurais pas eu l'idée de faire de l'allocation dynamique pour un std::string employé comme cela.
    --> Et oui je m'attendais à cette remarque

    --> Mais disons que pour commencer à utiliser les template et à comprendre leur fonctionnement, (car vous aurez compris que je débute avec), je migre une liste chainée de strings déjà écrite avec un type "char*".


    Tu laisses le constructeur par copie et l'opérateur d'assignement à leur version définie par le compilateur alors que le destructeur fait quelque chose, c'est mauvais signe et effectivement tu risques de libérer deux fois de la
    mémoire et d'avoir des fuites.

    C'est généralement pas une très bonne idée de passer par valeur des arguments dont le type est déterminé par un paramètre template, une référence constante va éviter des copies potentiellement coûteuses.
    --> Donc de manière générale, tu me conseilles de définir en plus le constructeur par copie, l'opérateur d'assignement, et de passer plutôt des références constantes.


    La solution à mon pb est donc d'écrire ce qu'à conseillé "Loufoque" ? :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    CMaillon(const T& x, CMaillon* s) : info(x), suiv(s){
    }
    Mais là non plus, info n'est pas alloué ... Donc je ne sais pas commment faire.

    @+

  9. #9
    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 olive_le_malin
    --> pour le delete je pensais que [] était utilisé si on libérait un tableau alloué.
    Comment veux-tu qu'en général le compilateur sache quel version de new a été utilisée? Ce n'est peut-être pas dans la même unité de compilation, ça dépend peut-être du chemin dans lequel on est passé.

    --> Mais disons que pour commencer à utiliser les template et à comprendre leur fonctionnement, (car vous aurez compris que je débute avec), je migre une liste chainée de strings déjà écrite avec un type "char*".
    Un exercice pour comprendre comment fonctionne les templates, c'est une raison valable de réinventer la roue. A condition d'en être conscient.

    Mais ça n'explique pas l'utilisation de char* pour les chaînes (au strict minimum, pourquoi pas char const*?).

    --> Donc de manière générale, tu me conseilles de définir en plus le constructeur par copie, l'opérateur d'assignement,
    Quand tu définis un destructeur, il est rare de ne pas avoir à au moins déclarer le constructeur par copie et l'assignement. Maintenant que tu les définisses en plus ou non ou que tu les déclares privés, c'est un choix de conception. Dans le cas de chaînons, j'aurais tendance à les déclarer privés et à ne pas les implémenter.

    et de passer plutôt des références constantes.
    En général, j'utilise des références constantes pour tout ce qui n'est pas type de base -- et les arguments templatisés n'en sont pas -- sauf quand j'ai une bonne raison de faire autrement.

    La solution à mon pb est donc d'écrire ce qu'à conseillé Loufoque" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CMaillon(const T& x, CMaillon* s) : info(x), suiv(s){
    }
    Et je suppose d'y ajouter les constructeurs et opérateurs manquants.
    Oui.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Par défaut
    Bonjour,

    mais je ne comprends toujours pas comment allouer mon "T info" ... ?

    @+

  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 olive_le_malin
    Bonjour,

    mais je ne comprends toujours pas comment allouer mon "T info" ... ?

    @+
    Qu'est-ce que tu ne comprends pas dans le message numéro 3 de la discussion?

  12. #12
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Si c'est un pointeur, tu dois l'initialiser avec new T(arguments).
    Si c'est un objet statique, tu dois l'initialiser dans la liste d'initialisation en faisant :
    Construct(...) : info(arguments), etc ...

Discussions similaires

  1. [Templates] Quel système utilisez-vous ? Pourquoi ?
    Par narmataru dans le forum Bibliothèques et frameworks
    Réponses: 270
    Dernier message: 26/03/2011, 00h15
  2. Template XHTML
    Par Sylvain James dans le forum XSL/XSLT/XPATH
    Réponses: 14
    Dernier message: 16/06/2003, 21h45
  3. appliquer plusieurs templates
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 04/04/2003, 16h26
  4. template match="node() mais pas text()"
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 26/03/2003, 10h52
  5. [XSLT] template
    Par demo dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 09/09/2002, 11h31

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