OVH Cloud OVH Cloud

Héritage et template

17 réponses
Avatar
Guillaume Gourdin
Bonjour à tous. Voilà, j'ai une classe template que je voudrais instancier
selon le type du template :

template <class T> class Pipo {};

// plus loin...
Pipo * pipo;
switch (Type)
{
case 0 : pipo = new Pipo<float>(); break;
case 1 : pipo = new Pipo<int>(); break;
case 2 : pipo = new Pipo<short>(); break;
}

Mais ce code ne compile pas sous VC6, car, grosso modo, le compilateur me
dit qu'il ne peut pas convertir de Pipo<float>* vers Pipo, idem pour les int
et les shorts.

Avez-vous des suggestions pour pallier ce genre de problème et avoir un
pointeur de template génétique quelques soit le type du template ? J'avais
pensé à créer une classe PipoFloat héritant de Pipo<float>, mais ça ne
semble pas résoudre le problème.

Merci.

10 réponses

1 2
Avatar
Michaël Monerau
Guillaume Gourdin wrote:
Avez-vous des suggestions pour pallier ce genre de problème et avoir
un pointeur de template génétique quelques soit le type du template ?
J'avais pensé à créer une classe PipoFloat héritant de Pipo<float>,
mais ça ne semble pas résoudre le problème.


Tu peux faire un :

class PipoBase
{
// tu mets ici les opérations que tu voudras
// pouvoir faire avec ton PipoBase*
// en virtuelle pure ou non, selon tes besoins
};

Et ensuite :

templace <class T> class Pipo : public PipoBase
{
// tu mets l'implémentation des fonctions
// qui en ont besoin...
}

Et maintenant, tu peux faire ton code :

##
PipoBase * pipo;
switch (Type)
{
case 0 : pipo = new Pipo<float>(); break;
case 1 : pipo = new Pipo<int>(); break;
case 2 : pipo = new Pipo<short>(); break;
}

pipo->UneFonctionDePipoBase ();
##

Le problème avec cette méthode, c'est que tu ne pas retourner un objet du
type du template par exemple (les fonctions de PipoBase ne peuvent pas
savoir qu'on va dériver en template...).

D'ailleurs, si quelqu'un a une solution pour palier à ce dernier problème,
je suis preneur :-)

Je ne sais pas si ça s'accomode à ce que tu veux faire...
--
<=- Michaël "Cortex" Monerau -=>

Avatar
Fabien LE LEZ
On Sun, 28 Sep 2003 20:28:01 +0200, "Guillaume Gourdin"
wrote:

template <class T> class Pipo {};

// plus loin...
Pipo * pipo;


Déjà, ceci ne devrait pas être accepté par le compilo.

A priori, la méthode pour résoudre ton problème est :

class Pipo_base
{
// Ici, les fonctions communes
};

template <class T> class Pipo : public Pipo_base
{
...
};

Pipo_base* pipo;

switch (...)
{
case 0 : pipo = new Pipo<float>; break;
case 1 : pipo = new Pipo<int>; break;

Avatar
Guillaume Gourdin
class Pipo_base
{
// Ici, les fonctions communes
};


Ca ne convient pas, car la classe Pipo traite des données qui elles aussi
sont typées par le template. Par ex.

template <class T> class Pipo
{
public:
void Set(const T & Data) {_Data = Data}
private:
T _Data;
};

Avatar
Fabien LE LEZ
On Sun, 28 Sep 2003 21:49:47 +0200, "Guillaume Gourdin"
wrote:

void Set(const T & Data) {_Data = Data}


Et comment voudrais-tu faire appel à une telle fonction en passant par
un "Pipo*" ?

Avatar
Christophe Lephay
"Fabien LE LEZ" a écrit dans le message de
news:
On Sun, 28 Sep 2003 21:49:47 +0200, "Guillaume Gourdin"

void Set(const T & Data) {_Data = Data}


Et comment voudrais-tu faire appel à une telle fonction en passant par
un "Pipo*" ?


Personnellement, je parlerais pas trop de Pipo à Gourdin, des fois que ça
l'excite ;)

Chris


Avatar
kanze
"Michaël Monerau" wrote in message
news:<Z0Gdb.164642$...
Guillaume Gourdin wrote:
Avez-vous des suggestions pour pallier ce genre de problème et avoir
un pointeur de template génétique quelques soit le type du template
? J'avais pensé à créer une classe PipoFloat héritant de
Pipo<float>, mais ça ne semble pas résoudre le problème.


Tu peux faire un :

class PipoBase
{
// tu mets ici les opérations que tu voudras
// pouvoir faire avec ton PipoBase*
// en virtuelle pure ou non, selon tes besoins
};

Et ensuite :

templace <class T> class Pipo : public PipoBase
{
// tu mets l'implémentation des fonctions
// qui en ont besoin...
}

Et maintenant, tu peux faire ton code :

##
PipoBase * pipo;
switch (Type)
{
case 0 : pipo = new Pipo<float>(); break;
case 1 : pipo = new Pipo<int>(); break;
case 2 : pipo = new Pipo<short>(); break;
}

pipo->UneFonctionDePipoBase ();
##

Le problème avec cette méthode, c'est que tu ne pas retourner un objet
du type du template par exemple (les fonctions de PipoBase ne peuvent
pas savoir qu'on va dériver en template...).

D'ailleurs, si quelqu'un a une solution pour palier à ce dernier
problème, je suis preneur :-)


Je crois que boost::any pourrait faire l'affaire. Mais je me poserais
des questions : pourquoi ? Qu'est-ce qu'on va réelement faire avec pipo ?

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
Michaël Monerau
wrote:
Le problème avec cette méthode, c'est que tu ne pas retourner un
objet du type du template par exemple (les fonctions de PipoBase ne
peuvent pas savoir qu'on va dériver en template...).

D'ailleurs, si quelqu'un a une solution pour palier à ce dernier
problème, je suis preneur :-)


Je crois que boost::any pourrait faire l'affaire. Mais je me poserais
des questions : pourquoi ? Qu'est-ce qu'on va réelement faire avec
pipo ?


J'avais eu le pb avec un système que je voulais implémenter : je voulais
faire une variable d'un type que l'on veut (int, float, types persos...), et
duquel on pourrait avoir la valeur. Comme un type intégral en fait, mais
encapsulé pour pouvoir traiter un vector de tels objets et les manipuler
chacun pareil. Voilà un code qui résume un peu (en raccourci) :

class UVarBase
{
public:
virtual xxx GetValue () const = 0;
};

template <class T>
class UVar
{
public:
typedef const_ref_type const T&;

virtual xxx GetValue () const = 0;
// je voudrais :
virtual const T& GetValue () const = 0;
};

Bon, je n'ai pas mis les opérateurs et les setteurs... Mais l'idée y est.
Dans la classe de base, on ne peut pas connaître le type template final. Du
coup, la fonction GetValue ne peut pas renvoyer le bon type directement.
Alors moi j'avais fait renvoyer un void*, que je recastais ensuite en
faisant confiance au programmeur qui appelait la fonction :

template <class T>
typename UVar<T>::const_ref_type UVarValue (const UVar<T>* pUVar)
{
return *(reinterpret_cast<UVar<T>::const_pointer_type>(pUVar->GetValue()));
}

Et donc, on pouvait avoir, avec une UVar, sa valeur. Maintenant, si on
voulait la valeur d'une UVarBase, j'avais fait :


Avatar
Michaël Monerau
Michaël Monerau wrote:
wrote:
template <class T>
typename UVar<T>::const_ref_type UVarValue (const UVar<T>* pUVar)
{
return
*(reinterpret_cast<UVar<T>::const_pointer_type>(pUVar->GetValue())); }

Et donc, on pouvait avoir, avec une UVar, sa valeur. Maintenant, si on
voulait la valeur d'une UVarBase, j'avais fait :


Zut... le message est parti trop vite. Je reprends :

Pour avoir la valeur d'une UVarBase, je faisais :

template <class T>
typename UVar<T>::const_ref_type UVarValue (const UVarBase* pUVarBase)
{
return UVarValue<T> (&pUVarBase->ToUVar<T> ());
}

et j'appelais :

UVarBase* pUVarBase = new UVar<float>;
// ...
UVarValue<float> (pUVarBase);
delete pUVarBase;

(en vérité, c'était pour un autre usage : une suite d'options dans un de mes
programmes... Mais bon).

Peut-être existe-t-il un meilleur idiôme pour faire ce que je voulais...

Mais ça me permettait d'avoir un vector<UVarBase*> et de pouvoir gérer
toutes les options facilement (à partir de leur nom). Mais ça impose de
faire très attention au paramètre template donne à UVarValue (UVarBase*).
--
<=- Michaël "Cortex" Monerau -=>

Avatar
Christophe Lephay
"Michaël Monerau" a écrit dans le message de
news:unXdb.181378$
J'avais eu le pb avec un système que je voulais implémenter : je voulais
faire une variable d'un type que l'on veut (int, float, types persos...),
et

duquel on pourrait avoir la valeur. Comme un type intégral en fait, mais
encapsulé pour pouvoir traiter un vector de tels objets et les manipuler
chacun pareil. Voilà un code qui résume un peu (en raccourci) :

class UVarBase
{
public:
virtual xxx GetValue () const = 0;
};

template <class T>
class UVar
{
public:
typedef const_ref_type const T&;

virtual xxx GetValue () const = 0;
// je voudrais :
virtual const T& GetValue () const = 0;
};


J'ai un jour été confronté à ce problème, et je l'ai résolu en passant par
un stream pour extraire la valeur...

Chris

Avatar
Michaël Monerau
Christophe Lephay wrote:
template <class T>
class UVar
{
public:
typedef const_ref_type const T&;

virtual xxx GetValue () const = 0;
// je voudrais :
virtual const T& GetValue () const = 0;
};


J'ai un jour été confronté à ce problème, et je l'ai résolu en
passant par un stream pour extraire la valeur...


C'est-à-dire ? Je ne vois pas ce que tu veux dire... Mon but est aussi de
passer par un stream ensuite pour l'afficher. Le type 'T' doit alors aussi
surcharger l'opérateur '<<' pour lui...

Mais si tu fais passer directement par un stream, comment récupérer
l'information si tu ne sais pas de quel type elle est ?
--
<=- Michaël "Cortex" Monerau -=>


1 2