OVH Cloud OVH Cloud

polymorphisme static

5 réponses
Avatar
foo
salut

je cherche un moyen d'appeler à partir d'une classe de base (template)
un membre d'une classe dérivé,

note 1/ get_wave ne peu pas etre virtual (performance, vtable...)
note 2/ get_wave ne peu pas etre static (utilisation membres freq & ampl)


pseudo code


template <typename T>
struct osc
{
protected:
float frequency;
float amplitude;

public:
float get_wave(); // polymorphisme static ???? comment faire
inline void work(float* buf, unsigned long len)
{
// foreach samples
osc<T>::get_wave();

}
};



struct sine : public osc<sine>
{
inline float get_wave()
{
// compute
}
};



//
sine osc;
osc.work(foo, 512); // erreur de link (get_wave de osc)


si quelqu'un a une idée ?

foo

5 réponses

Avatar
Franck Branjonneau
foo écrivait:

salut

je cherche un moyen d'appeler à partir d'une classe de base (template)
un membre d'une classe dérivé,

note 1/ get_wave ne peu pas etre virtual (performance, vtable...)
note 2/ get_wave ne peu pas etre static (utilisation membres freq & ampl)


La note 2 n'a pas de sens : rends explicite this.

pseudo code


template <typename T>
struct osc
{
protected:
float frequency;
float amplitude;

public:
float get_wave(); // polymorphisme static ???? comment faire


{ return T::get_wave(); }
--
Franck Branjonneau

Avatar
Vincent Richard

je cherche un moyen d'appeler à partir d'une classe de base (template)
un membre d'une classe dérivé,

note 1/ get_wave ne peu pas etre virtual (performance, vtable...)


Franchement, tu as mesuré les performances ? J'avais déjà posé une question
similaire ici, il y a quelques temps, et finalement j'avais fini par faire
des tests.

J'ai été extrêmement étonné des résultats...

 inline void work(float* buf, unsigned long len)
 {
     // foreach samples
     osc<T>::get_wave();


Si j'ai bien compris ce que tu veux faire, tu peux écrire :

dynamic_cast <osc <T>*>(this)->get_wave();

(et enlever la déclaration de get_wave() dans osc.)

Je n'ai pas essayé, donc je ne sais même pas si ça compile et encore moins
si c'est légal. Par contre, je doute que ça soit plus performant que la
fonction virtuelle...

Et dans le cas où get_wave() est virtuelle pure (virtual ...() = 0), je
suppose que le compilo doit se permettre un tas d'optimisations...

Vincent

--
vmime, une bibliothèque C++ sous licence GPL pour parser et générer
des messages au format MIME : http://www.sourceforge.net/projects/vmime/

Avatar
kanze
Vincent Richard wrote
in message news:<40cc0f57$0$13928$...

je cherche un moyen d'appeler à partir d'une classe de base
(template) un membre d'une classe dérivé,

note 1/ get_wave ne peu pas etre virtual (performance, vtable...)


Franchement, tu as mesuré les performances ? J'avais déjà posé une
question similaire ici, il y a quelques temps, et finalement j'avais
fini par faire des tests.

J'ai été extrêmement étonné des résultats...

inline void work(float* buf, unsigned long len)
{
// foreach samples
osc<T>::get_wave();


Si j'ai bien compris ce que tu veux faire, tu peux écrire :

dynamic_cast <osc <T>*>(this)->get_wave();

(et enlever la déclaration de get_wave() dans osc.)

Je n'ai pas essayé, donc je ne sais même pas si ça compile et encore
moins si c'est légal. Par contre, je doute que ça soit plus performant
que la fonction virtuelle...


Un dynamic_cast est prèsque sûrement moins performant que l'appel d'une
fonction virtuelle.

Il n'était pas tout à fait claire dans sa présentation. *Si* le type est
connu au moment de la compilation, comme c'était le cas dans son
exemple, il n'y a aucune différence dans les performances des fonctions
virtuelles et les performances des non-virtuelles. Si le type n'est pas
connu, et varie lors de l'execution, en général, les fonctions
virtuelles, c'est la solution la plus performante ; les alternatifs
(switch, etc.) sont en général encore moins rapide.

Dans la passée, je me suis servi d'un truc que j'ai appris de Barton et
Nackman, pour pouvoir se passer de la virtualité quand je connaissais le
type, tout en l'ayant quand je ne le connaissais pas. En gros, ça se
présentait un peu comme :

class Oscillation
{
public:
float getWave() const
{
return doGetWave() ;
}

private:
virtual float doGetWave() const = 0 ;
} ;

class Sine : public Oscillation
{
public:
float getWave() const ; // Avec la vraie implémentation

private:
virtual float doGetWave() const
{
return getWave() ;
}
} ;

Si j'appelle getWave à travers une référence à Oscillation, j'ai bien un
appel virtuel. Si je l'appelle à travers une référence à Sine, en
revanche, j'ai un appel direct à la fonction, sans virtualité.

Tel qu'il l'a présenté, je ne sais pas si ça lui conviendrait. J'avais
l'impression qu'il n'utilise pas le polymorphisme ; qu'il connaît
toujours le type en question. Dans ce cas-là, d'abord, on se pose la
question : pourquoi l'héritage. Si c'est la facturation du code commun
aux tous les oscillations, c'est effectivement une solution, mais je
verrais aujourd'hui plutôt une solution avec des traits, du genre :

template< typename Traits >
class Oscillation
{
// ...
void work( std::vector< float > const& buffer )
{
// ...
Traits::getWave( this ) ;
// ...
}
} ;

typedef Oscillation< SineTraits > Sine ;

Sinon, sa solution est aussi jouable, avec des static_cast dans la
classe de base :

static_cast< T >( this )->getWave() ;

Dans ce cas-ci, j'essaierais d'implémenter une vérification de concept
pour asserter que T dérive de Oscillation< T >. Quelque chose du genre :

Oscillation< T >* p = static_cast< T* >( 0 ) ;

dans le constructeur, par exemple.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Alexandre
dynamic_cast <osc <T>*>(this)->get_wave();



pour dynamic_cast ne faut-il pas que la classe ait une méthode virtuelle ?

Un dynamic_cast est prèsque sûrement moins performant que l'appel d'une
fonction virtuelle.


surement. De plus, je ne suis même pas sur qu'il ait un sens sans méthodes
virtuelles dans la classe...


Il n'était pas tout à fait claire dans sa présentation. *Si* le type est
connu au moment de la compilation, comme c'était le cas dans son
exemple, il n'y a aucune différence dans les performances des fonctions
virtuelles et les performances des non-virtuelles. Si le type n'est pas
connu, et varie lors de l'execution, en général, les fonctions
virtuelles, c'est la solution la plus performante ; les alternatifs
(switch, etc.) sont en général encore moins rapide.

Dans la passée, je me suis servi d'un truc que j'ai appris de Barton et
Nackman, pour pouvoir se passer de la virtualité quand je connaissais le
type, tout en l'ayant quand je ne le connaissais pas. En gros, ça se
présentait un peu comme :

class Oscillation
{
public:
float getWave() const
{
return doGetWave() ;
}

private:
virtual float doGetWave() const = 0 ;
} ;

class Sine : public Oscillation
{
public:
float getWave() const ; // Avec la vraie
implémentation


private:
virtual float doGetWave() const
{
return getWave() ;
}
} ;

Si j'appelle getWave à travers une référence à Oscillation, j'ai bien un
appel virtuel. Si je l'appelle à travers une référence à Sine, en
revanche, j'ai un appel direct à la fonction, sans virtualité.

Tel qu'il l'a présenté, je ne sais pas si ça lui conviendrait. J'avais
l'impression qu'il n'utilise pas le polymorphisme ; qu'il connaît
toujours le type en question. Dans ce cas-là, d'abord, on se pose la
question : pourquoi l'héritage. Si c'est la facturation du code commun
aux tous les oscillations, c'est effectivement une solution, mais je
verrais aujourd'hui plutôt une solution avec des traits, du genre :

template< typename Traits >
class Oscillation
{
// ...
void work( std::vector< float > const& buffer )
{
// ...
Traits::getWave( this ) ;
// ...
}
} ;

typedef Oscillation< SineTraits > Sine ;

Sinon, sa solution est aussi jouable, avec des static_cast dans la
classe de base :

static_cast< T >( this )->getWave() ;

Dans ce cas-ci, j'essaierais d'implémenter une vérification de concept
pour asserter que T dérive de Oscillation< T >. Quelque chose du genre :

Oscillation< T >* p = static_cast< T* >( 0 ) ;

dans le constructeur, par exemple.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
"Alexandre" wrote in message
news:<40cdd2d1$0$15342$...
dynamic_cast <osc <T>*>(this)->get_wave();



pour dynamic_cast ne faut-il pas que la classe ait une méthode
virtuelle ?


Tout à fait.

Le problème, c'est que tu as décris une partie d'une solution, mais non
le problème. Alors, on essaie de déviner. Ton code se basait sur un
héritage public ; neuf fois sur dix, l'héritage public sert à
l'implémentation du polymorphisme dynamique, à la OO. Ce qui suppose
aussi des fonctions virtuelles.

Si le but, c'est simplement de fournir une implémentation (ou une partie
d'implémentation) commune à la classe dérivée, sans que l'utilisateur
soit amené à « connaître » la classe de base, on préfère en général
l'héritage privé. Quand on ne peut pas se passer de l'héritage
complètement, au moyen de la délégation ou une classe de traits.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34