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 :

[template] surcharge operateur de flux, héritage et template


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 292
    Billets dans le blog
    2
    Par défaut [template] surcharge operateur de flux, héritage et template
    Bien le bonjour tout le monde,

    j'ai un petit soucis et je cherche la façon la plus élégante de le résoudre.

    J'ai une classe Mere, que je pourrais présenter comme suit, et son opérateur d'indirection de flux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Mere
    {
    friend std::ostream & operator << ( std::ostream & ostr, const Mere & mere );
     
    public:
       std::string name;
       int value;
    };
    Il se trouve que, les spécifications ayant changées, je dois implémenter différents comportements pour cette classe Mere. J'ai donc décidé d'utiliser le pattern template method et j'ai créé 2 classes Filles qui héritent de Mere et qui possèdent les même attributs. Seules quelques fonctions membres changent (c'est un cas typique de spécialisation):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Fille1 : public Mere
    { // code };
     
    class Fille2 : public Mere
    { // code };
    Maintenant ça se complique: j'ai une classe conteneur template, qui est vouée à prendre en paramètre template une des deux classes filles (j'ai fais comme ça car je suis sûr que les specs vont encore changer et qu'il va me falloir implémenter d'autres classes FilleX):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <class TypeElement> // TypeElement = Fille1 ou Fille2
    class TableauDeMere
    {
    // ici tout mon code. c'est un gros fourre-tout ce conteneur.
    private:
       std::set<TypeElement, MonFoncteurDeComparaison> m_leSet;
    }
    Le décor est planté, voilà le problème: je n'arrive pas à implémenter mon opérateur d'indirection de flux pour mon TableauDeMere.

    J'ai essayé ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template <class TypeElement> // TypeElement = Fille1 ou Fille2
    class TableauDeMere
    {
       friend std::ostream & operator << ( std::ostream & ostr, const TableauDeMere<TypeElement> & ad );
    //...
    }
    
    template <class TypeElement>
    std::ostream & operator << ( std::ostream & ostr, const TableauDeMere<TypeElement> & ad )
    {
    	std::copy( ad.m_leSet.begin(), ad.m_leSet.end(), std::ostream_iterator<Mere>(ostr, "\n"));
    // ici, Mere me parait le plus logique puisque je sais que quelque soit le type de TypeElement, il héritera de Mere. Et je veux utiliser l'operateur << de la classe Mere justement
    	return ostr;
    }
    Le code ci-dessus compile si je n'utilises pas l'operateur << de TableauDeMere. Lorsque je l'utilise (en essayant d'afficher un TableauDeMere<Fille1> par exemple), le compilo (j'utilise visual 2005 express ici) n'arrive pas à résoudre le typage:
    error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class TableauDeMere<class Fille1> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$TableauDeMere@VFille1@@@@@Z) referenced in function _main
    Voyez-vous mon problème? Voyez-vous une solution élégante?

  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,

    As tu, tout bêtement, implémenté l'opérateur << pour la classe mère idéalement, en te basant sur l'entrée de la FAQ qui traite de l'affichage d'objet polymorphes...

    De prime abord, c'est en effet au niveau de l'opérateur << des classes dérivées qu'il y a une absence à combler
    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
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 292
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,

    As tu, tout bêtement, implémenté l'opérateur << pour la classe mère
    Vivi: déclarée en amie de la classe Mere et implémentée.

    Citation Envoyé par koala01 Voir le message
    idéalement, en te basant sur l'entrée de la FAQ qui traite de l'affichage d'objet polymorphes...
    Vi, j'avais vu cette faq, mais elle ne répond pas à mon problème. En fait, moi je ne veux qu'un seul operateur << pour toutes mes classes filles, qui sera donc implémenté dans la classe mère.

    Citation Envoyé par koala01 Voir le message
    De prime abord, c'est en effet au niveau de l'opérateur << des classes dérivées qu'il y a une absence à combler
    Ben vi, mais où? (et surtout, pourquoi?)

  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 r0d Voir le message
    Vivi: déclarée en amie de la classe Mere et implémentée.
    désolé... la distraction aidant, c'était une solution "simple"

    ... mais je suis très distrait
    Vi, j'avais vu cette faq, mais elle ne répond pas à mon problème. En fait, moi je ne veux qu'un seul operateur << pour toutes mes classes filles, qui sera donc implémenté dans la classe mère.
    Evidemment, si la classe mere dispose de toutes les informations pour provoquer l'affichage correct...
    Ben vi, mais où? (et surtout, pourquoi?)
    La seule solution que j'envisage, c'est que, s'agissant d'une classe template, l'implémentation de l'opérateur << pour ta classe TableauDeMere
    n'est pas accessibe avec la seule inclusion du fichier d'en-tête dans lequel elle est définie...
    [EDIT] quand au pourquoi, il est simple: l'implémentation doit être accessible au départ du fichier d'en-tête de manière à permettre au compilateur de l'adapter selon le type de l'objet réellement utilisé
    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
    Membre expérimenté
    Profil pro
    Inscrit en
    Août 2007
    Messages
    190
    Détails du profil
    Informations personnelles :
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations forums :
    Inscription : Août 2007
    Messages : 190
    Par défaut
    Salut,

    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
    template <class TypeElement> // TypeElement = Fille1 ou Fille2
    class TableauDeMere;
    
    template <class TypeElement>
    std::ostream & operator << ( std::ostream &, const TableauDeMere<TypeElement> &);
    
    template <class TypeElement> // TypeElement = Fille1 ou Fille2
    class TableauDeMere
    {
       friend std::ostream & operator << <>( std::ostream & ostr, const TableauDeMere<TypeElement> & ad );
    //...
    }
    
    template <class TypeElement>
    std::ostream & operator << ( std::ostream & ostr, const TableauDeMere<TypeElement> & ad )
    {
    	std::copy( ad.m_leSet.begin(), ad.m_leSet.end(), std::ostream_iterator<Mere>(ostr, "\n"));
    // ici, Mere me parait le plus logique puisque je sais que quelque soit le type de TypeElement, il héritera de Mere. Et je veux utiliser l'operateur << de la classe Mere justement
    	return ostr;
    }
    Ca devrait résoudre ton problème. Le fait de rajouter <> (j'aurais pu mettre <TypeElement>) permet de signaler au compilateur que tu souhaites qu'une instance de ta classe TableauDeMere pour un type T soit amie avec l'instance de l'operateur << pour le même type T.

  6. #6
    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
    Le plus étrange dans l'histoire, c'est qu'un code proche de
    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
    class Mere
    {
    	public:
    		Mere(int i): i(i){}
    		virtual ~Mere(){}
    		friend ostream& operator<<(ostream& ofs, const Mere& m)
    		{
    		    ofs<<m.i<<" ok";
    		    return ofs;
    		}
    		bool operator <(const Mere& m) const
    		{return i<m.i;}
    	protected:
     
    	private:
    		int i;
    };
    class Fille : public Mere
    {
    	public:
    		Fille(int i):Mere(i){}
    		~Fille(){}
    	protected:
     
    	private:
     
    };
    template <class T>
    class TMySet
    {
        public:
        void insert(const T& toadd)
        {
            s.insert( toadd);
        }
        friend ostream& operator<<(ostream& ofs, const TMySet& m)
        {
            copy( m.s.begin(), m.s.end(), ostream_iterator<T>(ofs, "\n"));
            return ofs;
        }
        set<T> s;
    };
     
    int main(int argc, char* argv[])
    {
        TMySet<Fille> s;
        for(int i = 0;i<10; ++i)
            s.insert(Fille(i));
        cout<<s;
    	return 0;
    }
    (tout dans un seul fichier ) fonctionne sans problème chez moi (sous réserve d'inclure <iterator>...

    J'ai même essayé en mettant chaque classe dans un fichier séparé, et je n'ai eu aucun problème.

    Définitivement, j'ai l'impression que tu auras implémenté l'opérateur << de ta classe TableauDeMere dans un fichier qui n'est pas inclus dans le fichier d'en-tête correspondant.

    En effet, il n'y a que dans la configuration suivante:
    fichier "Mere.hpp"
    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
    #ifndef MERE_HPP_INCLUDED
    #define MERE_HPP_INCLUDED
    #include <iostream>
    using namespace std;
    class Mere
    {
        public:
            Mere(int i): i(i){}
            virtual ~Mere(){}
            friend ostream& operator<<(ostream& ofs, const Mere& m)
            {
                ofs<<m.i<<" ok";
                return ofs;
            }
            bool operator <(const Mere& m) const
            {return i<m.i;}
        protected:
        private:
            int i;
    };
    #endif // MERE_HPP_INCLUDED
    fichier Fille.hpp
    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
     
    #ifndef FILLE_HPP_INCLUDED
    #define FILLE_HPP_INCLUDED
    #include "Mere.hpp"
     
    class Fille : public Mere
    {
        public:
            Fille(int i):Mere(i){}
    		~Fille(){}
    	protected:
     
    	private:
     
    };
    #endif // FILLE_HPP_INCLUDED
    fichier "TMySet.hpp
    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
    #ifndef TMYSET_HPP_INCLUDED
    #define TMYSET_HPP_INCLUDED
    #include <set>
    #include <iostream>
    #include <iterator>
    using namespace std;template <class T>
    class TMySet
    {
        public:
            void insert(const T& toadd)
            {
                s.insert( toadd);
            }
            template<class I>
            friend ostream& operator<< (ostream& ofs, const TMySet<I>& m);
            set<T> s;
    };
    #endif // TMYSET_HPP_INCLUDED
    fichier TMySet.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include "TMySet.hpp"
    template < class I>
    ostream& operator<< (ostream& ofs,TMySet<I>&m)
    {
        copy( m.s.begin(), m.s.end(), ostream_iterator<I>(ofs, "\n"));
        return ofs;
    }
    fichier main.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "Fille.hpp"
    #include "TMySet.hpp"
     
    int main(int argc, char* argv[])
    {
        TMySet<Fille> s;
        for(int i = 0;i<10; ++i)
            s.insert(Fille(i));
        cout<<s;
    	return 0;
    }
    que j'arrive à reproduire une erreur similaire...
    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. souci classe template et surcharge operateur
    Par loicounet dans le forum Langage
    Réponses: 8
    Dernier message: 28/04/2008, 15h01
  2. Réponses: 2
    Dernier message: 05/01/2008, 23h39
  3. Optimisation Listechainé avec template et operateur surchargé.
    Par Alain Defrance dans le forum Langage
    Réponses: 8
    Dernier message: 29/12/2007, 18h25
  4. [Template] Surcharge operateur
    Par juls64 dans le forum C++
    Réponses: 7
    Dernier message: 04/05/2007, 19h35
  5. surcharge operateur delete et héritage
    Par Hervé dans le forum C++
    Réponses: 5
    Dernier message: 29/03/2006, 13h59

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