OVH Cloud OVH Cloud

Template

7 réponses
Avatar
Etienne Rousee
Bonjour,

le programme suivant génère une erreur à la compilation
(avec VC6). Que faut il que je fasse pour pouvoir faire
jouer le polymorphisme ? Le but est d'ensuite faire un
vecteur (ou autre conteneur) de pointeurs de LaMere et
d'y mettre des pointeurs de LeFils avec plusieurs T.


#include <iostream>

using namespace std;

class LaMere;
template <class T> class LeFils;

template <class T> ostream& operator<<(ostream&, LeFils<T> &);
template <class T> istream& operator>>(istream&, LeFils<T> &);

/********************************************************************/

class LaMere
{
public:
virtual void VirtPure(void) = 0;
};

/********************************************************************/

template <class T> class LeFils : public LaMere
{
public:

friend ostream& operator<<(ostream&, LeFils<T> &);
friend istream& operator>>(istream&, LeFils<T> &);

LeFils(T fils = 0) : _fils(fils) {}

void VirtPure(void) {};

protected:

T _fils;
};


template <class T> ostream& operator<<(ostream& os, LeFils<T> &fils)
{
os << "Et v'la l'fils : " << fils._fils << endl;

return os;
}


template <class T> istream& operator>>(istream& is, LeFils<T> &fils)
{
cout << "Entrez un fils : ";
is >> fils._fils;

return is;
}

int main(void)
{
LeFils<int> *toto = new LeFils<int>;
cin >> *toto;
cout << *toto;

LaMere *tutu = toto;
cout << *tutu; // Erreur ici

return EXIT_SUCCESS;
}

--

Etienne

7 réponses

Avatar
Fabien LE LEZ
On Sat, 10 Dec 2005 20:20:11 +0100, "Etienne Rousee"
:

Subject: Template


Mauvais sujet, ton problème n'a rien à voir avec les templates.

le programme suivant génère une erreur à la compilation
(avec VC6). Que faut il que je fasse pour pouvoir faire
jouer le polymorphisme ? Le but est d'ensuite faire un

vecteur


vector.
Ou "tableau", si tu préfères.
Un vecteur est un objet mathématique aux propriétés assez différentes.

[...]
LaMere *tutu = toto;
cout << *tutu; // Erreur ici


Ça ne marche pas, et il n'y a aucun moyen de faire ça, car "<<" ne
peut pas être membre.
Ce type de polymorphisme ne fonctionne qu'avec les fonctions
virtuelles.

Ce que tu peux faire :

//template<class T> /* Je le mets en commentaire car ça n'a rien à
voir avec le problème. */

class LaMere
{
public:
...
virtual void Print (ostream& os);// éventuellement, =0
};

class LeFils : public LaMere
{
public:
...
virtual void Print (ostream& os);
};

ostream& operator << (ostream& os, LaMere const& m)
{
m.Print (os);
return os;
}

Avatar
Etienne Rousee
"Fabien LE LEZ" a écrit ...
On Sat, 10 Dec 2005 20:20:11 +0100, "Etienne Rousee"
:

Subject: Template


Mauvais sujet, ton problème n'a rien à voir avec les templates.

le programme suivant génère une erreur à la compilation
(avec VC6). Que faut il que je fasse pour pouvoir faire
jouer le polymorphisme ? Le but est d'ensuite faire un

vecteur


vector.
Ou "tableau", si tu préfères.
Un vecteur est un objet mathématique aux propriétés assez différentes.


Oui, je me suis mal exprimé, quand je dis "vecteur" en français,
je pensais bien sûr au conteneur "vector" de la STL, de la même
façon que je pourrais parler d'une boucle "tant que".
Si le contexte était mathématique, je prendrais d'autres précautions.


[...]
LaMere *tutu = toto;
cout << *tutu; // Erreur ici


Ça ne marche pas, et il n'y a aucun moyen de faire ça, car "<<" ne
peut pas être membre.
Ce type de polymorphisme ne fonctionne qu'avec les fonctions
virtuelles.

Ce que tu peux faire :
............


Merci beaucoup, ceci fonctionne parfaitement maintenant:

#include <iostream>
#include <vector>

using namespace std;

/********************************************************************/

class LaMere;
template <class T> class LeFils;

template <class T> ostream& operator<<(ostream&, LeFils<T> &);
template <class T> istream& operator>>(istream&, LeFils<T> &);

/********************************************************************/

class LaMere
{
public:
virtual void print (ostream&) = 0;
};

ostream& operator<< (ostream& os, LaMere& mere)
{
mere.print (os);

return os;
}

/********************************************************************/

template <class T> class LeFils : public LaMere
{
public:

friend ostream& operator<<(ostream&, LeFils<T> &);
friend istream& operator>>(istream&, LeFils<T> &);

LeFils(T fils = 0) : _fils(fils) {}

virtual void print (ostream&);

protected:

T _fils;
};


template <class T> void LeFils<T>::print(ostream& os)
{
os << "Et v'la l'fils : " << _fils << endl;
}

template <class T> ostream& operator<<(ostream& os, LeFils<T> &fils)
{
fils.print(os);

return os;
}


template <class T> istream& operator>>(istream& is, LeFils<T> &fils)
{
cout << "Entrez un fils : ";
is >> fils._fils;

return is;
}

/********************************************************************/

int main(void)
{
vector <LaMere *> LeVecteur;
vector <LaMere *>::iterator it;

LeFils<int> *toto = new LeFils<int>;
cin >> *toto;
cout << *toto;
LeVecteur.push_back(toto);

LeFils<double> *titi = new LeFils<double>;
cin >> *titi;
cout << *titi;
LeVecteur.push_back(titi);

cout << endl;
for (it = LeVecteur.begin(); it != LeVecteur.end(); it++)
cout << **it;

return EXIT_SUCCESS;
}


Avatar
Falk Tannhäuser
Etienne Rousee wrote:
template <class T> ostream& operator<<(ostream&, LeFils<T> &);


J'espère que dans le programme réel c'est "LeFils<T> const&" !

template <class T> istream& operator>>(istream&, LeFils<T> &);

/********************************************************************/

class LaMere
{
public:
virtual void print (ostream&) = 0;


Pareil ici
virtual void print (ostream&) const = 0;
et partout ailleurs où il s'agit de sortir des objets -
le fait d'imprimer quelque chose ne doit d'habitude pas
modifier cette chose et c'est bien de le faire vérifier
par le compilateur.

[...]
template <class T> ostream& operator<<(ostream& os, LeFils<T> &fils)
{
fils.print(os);
return os;
}


Au fait, cet opérateur n'est plus nécessaire à partir du moment où
ostream& operator<<(ostream&, LaMere const&);
existe et fait appel à la fonction membre virtuelle "print(ostream&) const"
qui est redéfinie dans les classes "LeFils<T>".

[...]
int main(void)
{
vector <LaMere *> LeVecteur;
vector <LaMere *>::iterator it;
Je supprimerais cette définition ici...


LeFils<int> *toto = new LeFils<int>;
cin >> *toto;
cout << *toto;
LeVecteur.push_back(toto);

LeFils<double> *titi = new LeFils<double>;
cin >> *titi;
cout << *titi;
LeVecteur.push_back(titi);

cout << endl;
for (it = LeVecteur.begin(); it != LeVecteur.end(); it++)
... pour définir "it" ici comme étant un "vector<LaMere *>::const_iterator".


cout << **it;

return EXIT_SUCCESS;
}


Puis dans le programme réel, il faudra s'occuper de la durée de vie des
objets crées avec "new" :
- ne pas oublier le destructeur virtuel dans "LaMere",
- faire des "delete" quand il faut - le plus simple et le plus sûr,
c'est de les laisser faire par quelque chose comme "boost::shared_ptr".

Falk

Avatar
Etienne Rousee
"Falk Tannhäuser" a écrit ...

Oui, tu as raison.
Je voulais d'abord trouver le moyen de faire ce que je voulais
avant de le peaufiner pour le faire proprement.

--

Etienne
Avatar
Etienne Rousee
"Falk Tannhäuser" a écrit ...
Etienne Rousee wrote
template <class T> ostream& operator<<(ostream& os, LeFils<T> &fils)
{
fils.print(os);
return os;
}


Au fait, cet opérateur n'est plus nécessaire à partir du moment où
ostream& operator<<(ostream&, LaMere const&);
existe et fait appel à la fonction membre virtuelle "print(ostream&)
const"

qui est redéfinie dans les classes "LeFils<T>".


Et pourtant si.
En le mettant en commentaire, ça ne marche plus (erreur compilation).

--

Etienne


Avatar
Alexandre
template <class T> class LeFils : public LaMere
{
public:

friend ostream& operator<<(ostream&, LeFils<T> &);
friend istream& operator>>(istream&, LeFils<T> &);


la déclaration d'amitié est inutile, puisque ces opérateurs n'utilisent que
des membres publics.

template <class T> ostream& operator<<(ostream& os, LeFils<T> &fils)
{
fils.print(os);

return os;
}



inutile, puisque la définition de LaMere convient (print est virtuel...)
C'est l'interet du polymorphisme ;-)

Avatar
Etienne Rousee
"Alexandre" a écrit ...
template <class T> class LeFils : public LaMere
{
public:

friend ostream& operator<<(ostream&, LeFils<T> &);
friend istream& operator>>(istream&, LeFils<T> &);


la déclaration d'amitié est inutile, puisque ces opérateurs n'utilisent
que

des membres publics.


Ok pour operator<< mais pas pour operator>>.

template <class T> ostream& operator<<(ostream& os, LeFils<T> &fils)
{
fils.print(os);

return os;
}



inutile, puisque la définition de LaMere convient (print est virtuel...)
C'est l'interet du polymorphisme ;-)


Ben, VC6 ne veut pas s'en passer.

--

Etienne