Ben oui, mais non. Le polymorphisme ne marche qu'à travers des
références ou des pointeurs. Si l'on écrit
CTypeBase
ça veut dire que le type de l'objet est obligatoirement CTypeBase, et
non pas une classe dérivée ou une superclasse.
pourquoi ?
je peux tout à fait écrire virtual const ClasseDeBase operator+(const
ClasseDeBase &) const { return ClasseDerivee();} Ce qui m'intéresse,
c'est que ce soit le bon operator+ qui soit sélectionné.
Pour mon problème, j'ai trouvé une solution toute bête, dont voici le
code simplifié :
class CTypeInt;
class CTypeBase {
friend class CTypeInt;
public :
CTypeBase() : _ismissing(true) {}
CTypeBase(const CTypeBase &x) : _ismissing(x._ismissing) {}
const bool& is_missing(void) const { return _ismissing;}
void set_missing(void) { _ismissing=true;}
// opérateurs de base redéfinis
virtual const CTypeBase operator+(const CTypeBase&) const { return
CTypeBase();}
protected :
virtual const CTypeBase operator+(const CTypeInt&) const { return
CTypeBase();}
bool _ismissing;
};
class CTypeInt : public CTypeBase {
public :
CTypeInt() : CTypeBase() {}
CTypeInt(const CTypeInt &x) : CTypeBase(x),_value(x._value) {}
virtual const CTypeBase operator+(const CTypeBase&) const;
protected :
virtual const CTypeBase operator+(const CTypeInt&) const;
int _value;
};
En fait, je définis les opérateurs dans la classe de base, qui n'est
plus abstraite, même si je ne m'en servirai jamais.
J'ai trouvé sur Google une solution "esthétique" qui permet de
conserver la classe de base abstraite (avec des proxy), mais c'est une
usine à gaz qui rend le code incompréhensible et à mon avis peu
performant...
Pour info, l'implémentation de operator+ dans la classe dérivée serait
un truc du genre :
const CTypeBase CTypeInt::operator +(const CTypeBase &x) const
// implémentation : CTypeInt+CTypeBase retourne CTypeInt
{
if (_ismissing || x._ismissing)
return CTypeInt();
else
return x.operator +(*this);
}
const CTypeBase CTypeInt::operator +(const CTypeInt &x) const
{
CTypeInt entier;
if (_ismissing || x._ismissing)
return entier;
entier._ismissingúlse;
entier._value=_value+x._value;
return entier;
}
J'espère que je reste compréhensible...
Ben oui, mais non. Le polymorphisme ne marche qu'à travers des
références ou des pointeurs. Si l'on écrit
CTypeBase
ça veut dire que le type de l'objet est obligatoirement CTypeBase, et
non pas une classe dérivée ou une superclasse.
pourquoi ?
je peux tout à fait écrire virtual const ClasseDeBase operator+(const
ClasseDeBase &) const { return ClasseDerivee();} Ce qui m'intéresse,
c'est que ce soit le bon operator+ qui soit sélectionné.
Pour mon problème, j'ai trouvé une solution toute bête, dont voici le
code simplifié :
class CTypeInt;
class CTypeBase {
friend class CTypeInt;
public :
CTypeBase() : _ismissing(true) {}
CTypeBase(const CTypeBase &x) : _ismissing(x._ismissing) {}
const bool& is_missing(void) const { return _ismissing;}
void set_missing(void) { _ismissing=true;}
// opérateurs de base redéfinis
virtual const CTypeBase operator+(const CTypeBase&) const { return
CTypeBase();}
protected :
virtual const CTypeBase operator+(const CTypeInt&) const { return
CTypeBase();}
bool _ismissing;
};
class CTypeInt : public CTypeBase {
public :
CTypeInt() : CTypeBase() {}
CTypeInt(const CTypeInt &x) : CTypeBase(x),_value(x._value) {}
virtual const CTypeBase operator+(const CTypeBase&) const;
protected :
virtual const CTypeBase operator+(const CTypeInt&) const;
int _value;
};
En fait, je définis les opérateurs dans la classe de base, qui n'est
plus abstraite, même si je ne m'en servirai jamais.
J'ai trouvé sur Google une solution "esthétique" qui permet de
conserver la classe de base abstraite (avec des proxy), mais c'est une
usine à gaz qui rend le code incompréhensible et à mon avis peu
performant...
Pour info, l'implémentation de operator+ dans la classe dérivée serait
un truc du genre :
const CTypeBase CTypeInt::operator +(const CTypeBase &x) const
// implémentation : CTypeInt+CTypeBase retourne CTypeInt
{
if (_ismissing || x._ismissing)
return CTypeInt();
else
return x.operator +(*this);
}
const CTypeBase CTypeInt::operator +(const CTypeInt &x) const
{
CTypeInt entier;
if (_ismissing || x._ismissing)
return entier;
entier._ismissingúlse;
entier._value=_value+x._value;
return entier;
}
J'espère que je reste compréhensible...
Ben oui, mais non. Le polymorphisme ne marche qu'à travers des
références ou des pointeurs. Si l'on écrit
CTypeBase
ça veut dire que le type de l'objet est obligatoirement CTypeBase, et
non pas une classe dérivée ou une superclasse.
pourquoi ?
je peux tout à fait écrire virtual const ClasseDeBase operator+(const
ClasseDeBase &) const { return ClasseDerivee();} Ce qui m'intéresse,
c'est que ce soit le bon operator+ qui soit sélectionné.
Pour mon problème, j'ai trouvé une solution toute bête, dont voici le
code simplifié :
class CTypeInt;
class CTypeBase {
friend class CTypeInt;
public :
CTypeBase() : _ismissing(true) {}
CTypeBase(const CTypeBase &x) : _ismissing(x._ismissing) {}
const bool& is_missing(void) const { return _ismissing;}
void set_missing(void) { _ismissing=true;}
// opérateurs de base redéfinis
virtual const CTypeBase operator+(const CTypeBase&) const { return
CTypeBase();}
protected :
virtual const CTypeBase operator+(const CTypeInt&) const { return
CTypeBase();}
bool _ismissing;
};
class CTypeInt : public CTypeBase {
public :
CTypeInt() : CTypeBase() {}
CTypeInt(const CTypeInt &x) : CTypeBase(x),_value(x._value) {}
virtual const CTypeBase operator+(const CTypeBase&) const;
protected :
virtual const CTypeBase operator+(const CTypeInt&) const;
int _value;
};
En fait, je définis les opérateurs dans la classe de base, qui n'est
plus abstraite, même si je ne m'en servirai jamais.
J'ai trouvé sur Google une solution "esthétique" qui permet de
conserver la classe de base abstraite (avec des proxy), mais c'est une
usine à gaz qui rend le code incompréhensible et à mon avis peu
performant...
Pour info, l'implémentation de operator+ dans la classe dérivée serait
un truc du genre :
const CTypeBase CTypeInt::operator +(const CTypeBase &x) const
// implémentation : CTypeInt+CTypeBase retourne CTypeInt
{
if (_ismissing || x._ismissing)
return CTypeInt();
else
return x.operator +(*this);
}
const CTypeBase CTypeInt::operator +(const CTypeInt &x) const
{
CTypeInt entier;
if (_ismissing || x._ismissing)
return entier;
entier._ismissingúlse;
entier._value=_value+x._value;
return entier;
}
J'espère que je reste compréhensible...
Marc wrote:
Tu as deux solutions pour résoudre ton problème. La première est le
double-dispatch.
[...]
La deuxième façon, plus modulaire, consiste à utiliser l'idiome
lettre-enveloppe qu'évoque Jean-Marc.
Marc wrote:
Tu as deux solutions pour résoudre ton problème. La première est le
double-dispatch.
[...]
La deuxième façon, plus modulaire, consiste à utiliser l'idiome
lettre-enveloppe qu'évoque Jean-Marc.
Marc wrote:
Tu as deux solutions pour résoudre ton problème. La première est le
double-dispatch.
[...]
La deuxième façon, plus modulaire, consiste à utiliser l'idiome
lettre-enveloppe qu'évoque Jean-Marc.
la réponse est prèsque toujours
l'idiome lettre-envéloppe.
la réponse est prèsque toujours
l'idiome lettre-envéloppe.
la réponse est prèsque toujours
l'idiome lettre-envéloppe.
Avant de te lancer dans le codage, je te conseille de faire des
recherches sur l'idiome enveloppe-lettre, mon exemple n'ayant eu
pour but que de t'expliquer l'idée générale (l'utiliser tel quel
serait source de problèmes)...
J'avais déjà implémenté ce modèle avec une classe "enveloppe"
externe... Ton modèle me pousse à chercher à mettre cette classe tout
au sommet de la hierarchie, ce qui facilite l'écriture et même
l'efficacité à ce qu'il me semble...
Avant de te lancer dans le codage, je te conseille de faire des
recherches sur l'idiome enveloppe-lettre, mon exemple n'ayant eu
pour but que de t'expliquer l'idée générale (l'utiliser tel quel
serait source de problèmes)...
J'avais déjà implémenté ce modèle avec une classe "enveloppe"
externe... Ton modèle me pousse à chercher à mettre cette classe tout
au sommet de la hierarchie, ce qui facilite l'écriture et même
l'efficacité à ce qu'il me semble...
Avant de te lancer dans le codage, je te conseille de faire des
recherches sur l'idiome enveloppe-lettre, mon exemple n'ayant eu
pour but que de t'expliquer l'idée générale (l'utiliser tel quel
serait source de problèmes)...
J'avais déjà implémenté ce modèle avec une classe "enveloppe"
externe... Ton modèle me pousse à chercher à mettre cette classe tout
au sommet de la hierarchie, ce qui facilite l'écriture et même
l'efficacité à ce qu'il me semble...
la réponse est prèsque toujours l'idiome lettre-envéloppe.
Ce modèle est tout à fait adapté aux classes "volumineuses" et
complexes. Le problème est qu'il n'est pas très performant en terme de
vitesse d'exécution.
En effet dans l'opérateur +, il faut en général
1) recopier l'opérande gauche
2) appeler += polymorphe
3) recopier une nouvelle fois le résultat pour renvoyer un pointeur
Conclusion : ça rame pas mal
Autre solution possible que j'ai implémentée :
retour par référence vers un tampon fixe dans operator +
dans le fichier de définition de la classe de base
CTypeBase *CTypeBase::mainbufferPtr=NULL; // static
//-------------------------------------------------------
CTypeBase& CTypeBase::operator+(const CTypeBase &x) const
//-------------------------------------------------------
{
if (mainbufferPtr!=this) tobuffer();
mainbufferPtr->operator +=(x);
return *mainbufferPtr;
}
dans le fichier de définition d'une classe dérivée
CTypeInt CTypeInt::typeint; // static
void CTypeInt::touffer(void) const
{
//mises à jour du buffer typeint
.....
CTypeBase::mainbufferPtr=&typeint;
}
tobuffer() est une fonction virtuelle (pure dans CTypeBase) qui permet
à jour la variable globale dans l'unité concernée et indique ensuite
l'adresse de cette variable globale.
Seul inconvénient : une donnée membre statique par classe dérivée.
Dans mon cas, cette implémentation s'avère 15 fois + rapide que le
modèle proxy...
la réponse est prèsque toujours l'idiome lettre-envéloppe.
Ce modèle est tout à fait adapté aux classes "volumineuses" et
complexes. Le problème est qu'il n'est pas très performant en terme de
vitesse d'exécution.
En effet dans l'opérateur +, il faut en général
1) recopier l'opérande gauche
2) appeler += polymorphe
3) recopier une nouvelle fois le résultat pour renvoyer un pointeur
Conclusion : ça rame pas mal
Autre solution possible que j'ai implémentée :
retour par référence vers un tampon fixe dans operator +
dans le fichier de définition de la classe de base
CTypeBase *CTypeBase::mainbufferPtr=NULL; // static
//-------------------------------------------------------
CTypeBase& CTypeBase::operator+(const CTypeBase &x) const
//-------------------------------------------------------
{
if (mainbufferPtr!=this) tobuffer();
mainbufferPtr->operator +=(x);
return *mainbufferPtr;
}
dans le fichier de définition d'une classe dérivée
CTypeInt CTypeInt::typeint; // static
void CTypeInt::touffer(void) const
{
//mises à jour du buffer typeint
.....
CTypeBase::mainbufferPtr=&typeint;
}
tobuffer() est une fonction virtuelle (pure dans CTypeBase) qui permet
à jour la variable globale dans l'unité concernée et indique ensuite
l'adresse de cette variable globale.
Seul inconvénient : une donnée membre statique par classe dérivée.
Dans mon cas, cette implémentation s'avère 15 fois + rapide que le
modèle proxy...
la réponse est prèsque toujours l'idiome lettre-envéloppe.
Ce modèle est tout à fait adapté aux classes "volumineuses" et
complexes. Le problème est qu'il n'est pas très performant en terme de
vitesse d'exécution.
En effet dans l'opérateur +, il faut en général
1) recopier l'opérande gauche
2) appeler += polymorphe
3) recopier une nouvelle fois le résultat pour renvoyer un pointeur
Conclusion : ça rame pas mal
Autre solution possible que j'ai implémentée :
retour par référence vers un tampon fixe dans operator +
dans le fichier de définition de la classe de base
CTypeBase *CTypeBase::mainbufferPtr=NULL; // static
//-------------------------------------------------------
CTypeBase& CTypeBase::operator+(const CTypeBase &x) const
//-------------------------------------------------------
{
if (mainbufferPtr!=this) tobuffer();
mainbufferPtr->operator +=(x);
return *mainbufferPtr;
}
dans le fichier de définition d'une classe dérivée
CTypeInt CTypeInt::typeint; // static
void CTypeInt::touffer(void) const
{
//mises à jour du buffer typeint
.....
CTypeBase::mainbufferPtr=&typeint;
}
tobuffer() est une fonction virtuelle (pure dans CTypeBase) qui permet
à jour la variable globale dans l'unité concernée et indique ensuite
l'adresse de cette variable globale.
Seul inconvénient : une donnée membre statique par classe dérivée.
Dans mon cas, cette implémentation s'avère 15 fois + rapide que le
modèle proxy...
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers, j'ai voulu simplifier pour ne pas compliquer le
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers, j'ai voulu simplifier pour ne pas compliquer le
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers, j'ai voulu simplifier pour ne pas compliquer le
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers,
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers,
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers,
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers, j'ai voulu simplifier pour ne pas compliquer le
code transmis et je me suis trompé...Et c'est cette version tout à fait
correcte
qui va 15 fois plus vite que la version du type modèle proxy !
//-------------------------------------------------------
CTypeBase& CTypeBase::operator+(const CTypeBase &x) const
//-------------------------------------------------------
{
if (mainbufferPtr==&x) x.tosecondbuffer();
else secondbufferPtr=&x;
if (mainbufferPtr!=this) tomainbuffer();
mainbufferPtr->operator +=(*secondbufferPtr);
return *mainbufferPtr;
}
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers, j'ai voulu simplifier pour ne pas compliquer le
code transmis et je me suis trompé...Et c'est cette version tout à fait
correcte
qui va 15 fois plus vite que la version du type modèle proxy !
//-------------------------------------------------------
CTypeBase& CTypeBase::operator+(const CTypeBase &x) const
//-------------------------------------------------------
{
if (mainbufferPtr==&x) x.tosecondbuffer();
else secondbufferPtr=&x;
if (mainbufferPtr!=this) tomainbuffer();
mainbufferPtr->operator +=(*secondbufferPtr);
return *mainbufferPtr;
}
En somme, tu te sers d'un static pour le temporaire. Et qu'est-ce qui se
passe si tu as besoin de plus d'un temporaire à la fois ? Quelque chose
du genre :
(a + b) * (c + d)
par exemple. Tu vas utiliser le même mainbuffer pour le résultats de a +
b et les résultats de c + d ?
En fait, j'ai 2 buffers, j'ai voulu simplifier pour ne pas compliquer le
code transmis et je me suis trompé...Et c'est cette version tout à fait
correcte
qui va 15 fois plus vite que la version du type modèle proxy !
//-------------------------------------------------------
CTypeBase& CTypeBase::operator+(const CTypeBase &x) const
//-------------------------------------------------------
{
if (mainbufferPtr==&x) x.tosecondbuffer();
else secondbufferPtr=&x;
if (mainbufferPtr!=this) tomainbuffer();
mainbufferPtr->operator +=(*secondbufferPtr);
return *mainbufferPtr;
}
void f(CTypeBase&, int nbBuf) {
if (nbBuf >= 0) {
f(a + b, nbBuf-1);
}
}
Excuse-moi, mais je ne comprends pas bien ce que fais cette fonction...
void f(CTypeBase&, int nbBuf) {
if (nbBuf >= 0) {
f(a + b, nbBuf-1);
}
}
Excuse-moi, mais je ne comprends pas bien ce que fais cette fonction...
void f(CTypeBase&, int nbBuf) {
if (nbBuf >= 0) {
f(a + b, nbBuf-1);
}
}
Excuse-moi, mais je ne comprends pas bien ce que fais cette fonction...
void f(CTypeBase&, int nbBuf) {
if (nbBuf >= 0) {
f(a + b, nbBuf-1);
}
}
Excuse-moi, mais je ne comprends pas bien ce que fais cette
fonction...
void f(CTypeBase&, int nbBuf) {
if (nbBuf >= 0) {
f(a + b, nbBuf-1);
}
}
Excuse-moi, mais je ne comprends pas bien ce que fais cette
fonction...
void f(CTypeBase&, int nbBuf) {
if (nbBuf >= 0) {
f(a + b, nbBuf-1);
}
}
Excuse-moi, mais je ne comprends pas bien ce que fais cette
fonction...