 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Marc Guest
|
Posted: Sun Jan 18, 2004 10:30 am Post subject: Rédéfinition de l'opérateur + dans toute une hierarchie de c |
|
|
Bonjour,
j'ai une hierarchie de classes définie par exemple comme suit :
CBase
| Quote: |
----------------------------------------------------
| |
etc... |
CType1 CType2 CType3
| Quote: |
-----------------
|
CType31 CType32 |
Je voudrais redéfinir l'opérateur + de telle sorte que je puisse additionner
tous les types à partir de pointeurs/références sur la classe de base.
CBase {
....
virtual CBase& operator+(const CBase&);
....
};
CType1 {
....
virtual CBase& operator+(const CBase&);
CBase& operator+(const CType2&);
CBase& operator+(const CType3&);
....
};
etc...
Le problème, c'est que lorsque je fais
CBase &type1=CType1();
CBase &type2=CType2();
type1+type2;
je détermine bien dynamiquement l'opérande gauche de l'opérateur (définition
virtuelle de celui-ci), mais pas l'opérande droite, qui doit me permettre
d'appeler l'implémentation appropriée de l'opérateur !
Je suis donc obligé de faire un switch intégral dans la fonction
virtual CBase& CType1::operator+(const CBase&)
pour déterminer le type de l'opérande droite et appeler la fonction
appropriée ! (évidement, ça permet quand même de détecter le type d'addition
demandé et de vérifier qu'elle est bien définie dans la classe si jamais on
ajoute d'autres classes à la hierarchie, ce qui est quand même plus
prudent..).
Ma question : y-a-il un moyen d'éviter ceci !? Je n'ai pas trouvé...
Merci
|
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Mon Jan 19, 2004 7:52 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
On Sun, 18 Jan 2004 11:30:49 +0100, "Marc" <metrica (AT) free (DOT) fr> wrote:
| Quote: | CBase &type1=CType1();
|
C'est bizarre que ton compilo n'ait pas ralé : "CType1()" crée un
temporaire, et la référence "type1" ne pointe plus sur rien après
cette ligne.
Une écriture correcte serait :
CType1 mon_objet_type1;
CBase& type1= mon_objet_type1;
| Quote: | virtual CBase& operator+(const CBase&);
|
Pas bon non plus : operator+ crée un nouvel objet, renvoyer une
référence est donc une erreur.
Prenons une hiérarchie un peu plus simple : une classe "Base", et des
classes dérivées A et B :
Base
__|__
Si on peut ajouter un A et un B, de quel type est le résultat ?
--
;-)
http://www.gotw.ca/gotw/063.htm
http://www.gotw.ca/gotw/067.htm#2
|
|
| Back to top |
|
 |
Sylvain Togni Guest
|
Posted: Mon Jan 19, 2004 11:13 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
"Marc" <metrica (AT) free (DOT) fr> a écrit :
| Quote: | Bonjour,
j'ai une hierarchie de classes définie par exemple comme suit :
CBase
|
----------------------------------------------------
| | |
etc...
CType1 CType2 CType3
|
-----------------
| |
CType31 CType32
Je voudrais redéfinir l'opérateur + de telle sorte que je puisse
additionner
tous les types à partir de pointeurs/références sur la classe de base.
|
Le pattern du « double dispatch » résoud ce genre de problème.
L'astuce consiste, dans la fonction virtuelle operator+, à appeler
une seconde fonction virtuelle, mais cette fois-ci sur l'argument x.
class CBase
{
public:
virtual CBase& operator+(const CBase&) const = 0;
protected:
virtual CBase& addFromType1(const CType1&) const = 0;
virtual CBase& addFromType2(const CType2&) const = 0;
// ...
};
class CType1 : public CBase
{
public:
virtual CBase& operator+(const CBase& x) const
{
return x.addFromType1(*this);
}
protected:
virtual CBase& addFromType1(const CType1& x) const
{
// ...
}
virtual CBase& addFromType2(const CType2& x) const
{
// ...
}
// ...
};
Sylvain
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Tue Jan 20, 2004 7:49 am Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
"Marc" <metrica (AT) free (DOT) fr> wrote
| Quote: | j'ai une hierarchie de classes définie par exemple comme suit :
CBase
|
----------------------------------------------------
| | |
etc...
CType1 CType2 CType3
|
-----------------
| |
CType31 CType32
Je voudrais redéfinir l'opérateur + de telle sorte que je puisse
additionner tous les types à partir de pointeurs/références sur la
classe de base.
|
Et qu'est-ce qu'il doit renvoyer ? Un opérateur +, au moins d'en abuser,
renvoyer un nouvel objet. Par valeur. Quel doit être le type de cet
objet ?
| Quote: | CBase {
...
virtual CBase& operator+(const CBase&);
|
Tu renvoies une référence. À quoi ? La sémantique normale de + exige un
nouvel objet. Où est-ce que tu le mets si tu en renvoies une référence.
En général, les opérateurs arithmétiques et la sémantique de référence
ne fonctionnent pas bien ensemble en C++. Et par défaut, le
polymorphisme dynamique exige une sémantique de référence.
En fait, s'il s'agit d'une hièrarchie de types arithmétiques, c'est
précisemment le problème auquel Coplien s'adresse avec l'idiome de
lettre/envellope. Il y traite aussi la question du « double dispatch »
(c-à-d que la fonction réelement appelée dépend des deux types, et non
seulement d'un). Si tu cherches à faire quelque chose de pareil, je te
conseille très fort de le lire d'abord. (« Advanced C++ Programming
Styles and Idioms », James Coplien, Addison-Wesley, ISBN 0-201-54855-0.
Il n'est pas tout récent, mais pour ton problème, je ne connais pas de
mieux plus récent.)
--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
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
|
|
| Back to top |
|
 |
Marc Guest
|
Posted: Tue Jan 20, 2004 1:03 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
| Quote: | CBase &type1=CType1();
C'est bizarre que ton compilo n'ait pas ralé : "CType1()" crée un
temporaire, et la référence "type1" ne pointe plus sur rien après
cette ligne.
|
Mon compilo n'a pas calé parce que je ne lui ai pas soumis ce code...
Bon, j'ai plutôt l'habitude de manipuler des pointeurs et donc d'écrire qlq
chose du genre
CBase *p=new CType1();
ce qui est parfaitement correct...
J'avoue que je trouve dommage que l'écriture
CBase &type1=CType1();
ne soit pas acceptée.
C'est parce que le constructeur ne retourne aucun objet ? et que CType1()
n'étant pas "nommé", il est créé puis détruit ?
sinon, pour ce qui est des règles de portée, cette écriture ne devrait pas
poser de problème...
| Quote: | virtual CBase& operator+(const CBase&);
Pas bon non plus : operator+ crée un nouvel objet, renvoyer une
référence est donc une erreur.
|
là, j'avoue que le & est une faute d'étourderie
| Quote: | Base
__|__
| |
A B
Si on peut ajouter un A et un B, de quel type est le résultat ?
|
En fait ma classe de base ne me sert que pour déclarer des méthodes communes
virtuelles "supportées" par toutes les autres.
Par exemple :
A est un entier
B est un vecteur
B+A retourne un vecteur
A+B lance une exception
Je développe un interpréteur et cette organisation me facilite grandement
l'analyse contextuelle à partir de l'arbre syntaxique.
Le pattern du « double dispatch » proposé par Sylvain Togni résoud mon
problème.
Excuse-moi si je n'ai pas été clair et assez approximatif dans ma syntaxe.
Merci.
|
|
| Back to top |
|
 |
Marc Guest
|
Posted: Tue Jan 20, 2004 1:10 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
Merci pour tes explications,
c'est exactement la réponse qu'il me fallait.
En me creusant les neuronnes, j'aurais sans doute pu trouver une astuce dans
le genre mais je dois dire qu'un tel code perd quand même en lisibilité !
Comme dans chaque classe, il faut bien sûr systématiquement redéfinir
l'opérateur pour toutes les combinaisons possibles des types, n'est t-il pas
plus simple (et au moins aussi performant) de faire un switch(...), même si
c'est moins élégant ?
Qu'en penses-tu ?
Marc
|
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Tue Jan 20, 2004 6:06 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
On Tue, 20 Jan 2004 14:03:26 +0100, "Marc" <metrica (AT) free (DOT) fr> wrote:
| Quote: | J'avoue que je trouve dommage que l'écriture
CBase &type1=CType1();
ne soit pas acceptée.
|
Dans quel(s) cas verrais-tu une utilité ?
Note : une des utilités de l'allocation dynamique est justement la
gestion du polymorphisme d'héritage, du coup l'écriture
CBase *p=new CType1();
est assez courante.
--
;-)
http://www.gotw.ca/gotw/063.htm
http://www.gotw.ca/gotw/067.htm#2
|
|
| Back to top |
|
 |
Michel Michaud Guest
|
Posted: Tue Jan 20, 2004 8:00 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
Dans news:0frq00hpmej8nno2ab4jdte9u80a06p5ge (AT) 4ax (DOT) com, Fabien LE
LEZ <gramster (AT) gramster (DOT) com> a écrit :
| Quote: | Note : une des utilités de l'allocation dynamique est justement la
gestion du polymorphisme d'héritage, du coup l'écriture
CBase *p=new CType1();
est assez courante.
|
Pas en C++ :
CBase *p=new CType1;
fonctionne aussi normalement ! :-)
--
Michel Michaud [email]mm (AT) gdzid (DOT) com[/email]
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
|
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Tue Jan 20, 2004 8:47 pm Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
On Tue, 20 Jan 2004 15:00:40 -0500, "Michel Michaud" <mm (AT) gdzid (DOT) com>
wrote:
| Quote: | CBase *p=new CType1;
fonctionne aussi normalement !
|
Argh, les pièges du copier-coller ! ~_~
--
;-)
http://www.gotw.ca/gotw/063.htm
http://www.gotw.ca/gotw/067.htm#2
|
|
| Back to top |
|
 |
Gourgouilloult Guest
|
Posted: Fri Jan 23, 2004 5:14 am Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
Marc a écrit :
| Quote: |
un tel code perd quand même en lisibilité !
|
Pour ne pas trop surcharger, tu peux toujours ne pas définir tes
fonctions membres en inline (du point de vue géographique).
| Quote: | Comme dans chaque classe, il faut bien sûr systématiquement redéfinir
l'opérateur pour toutes les combinaisons possibles des types, n'est t-il pas
plus simple (et au moins aussi performant) de faire un switch(...), même si
c'est moins élégant ?
|
Je n'ai pas le sentiment que ça soit pareil. Quand tu passes dans un
truc comme :
CBase& CType1::operator+(const CBase& x) const
{
return x.addFromType1(*this);
}
dans l'appel x.addFromType1(*this), x est un objet considéré comme un
CBase du point de vue du compilo, mais à l'exécution, il «sait» à quelle
classe il appartient effectivement. Classe qui (schématiquement) dispose
d'un tableau associant à chaque fonction membre virtuelle une définition
précise. Donc x.addFromType1() est résolu en complexité constante. (1)
A l'opposé, si tu utilises un switch, tu vas avoir une suite de tests en
complexité linéaire. C'est à dire que chaque fois que tu rajoutes un
type à la hiérarchie, tu rajoutes un test supplémentaire, qui prendra
potentiellement plus de «temps» à l'exécution, contrairement à la
solution avec héritage.
Une réponse plus fervente serait de s'en tenir à dire qu'une des façons
de faire « est C » et l'autre « est C++ » ;)
(1) Euh... en fait, je trouverais logique que ça marche bien comme ça,
mais essentiellement dans le sens où on n'a pas de surcharge de
X::addFromType1(), quelque soit la classe X de la hiérarchie.
Comme je ne me souviens pas avoir étudié la question de la résolution de
surcharge de fonctions virtuelles (2), y a-t-il un pro qui pourrait
brièvement m'éclairer ? Est-ce que ça passe tout simplement (par
exemple, si on avait nommé les fonctions sur la base de :
CBase::addFromOtherType (CType1 & const) const
CBase::addFromOtherType (CType2 & const) const
(Ca ne me semble pas impossible non plus dans ce cas précis, puisque
dans l'expression « x.addFromOtherType (*this) », this a toujours un
type bien connu. Mais ça reste un cas particulier... et je ne vois pas
bien ce qui arrive à mon histoire de complexités.)
(2) En fait, j'suis pas très calé en résolution de surcharges tout
court. D'où une deuxième question, plus classique : j'ai pas dit trop de
bêtises ?
Gourgouilloult du Clapotis
|
|
| Back to top |
|
 |
Gourgouilloult Guest
|
Posted: Fri Jan 23, 2004 5:18 am Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
| Quote: | CBase& CType1::operator+(const CBase& x) const
|
Oui bon, en omettant la question du retour par référence, on va dire.
(En fait, je me suis plus intéressé à la façon de descendre dans la pile
d'appels, pas à ce qu'on en remonte.)
|
|
| Back to top |
|
 |
Andre Heinen Guest
|
Posted: Fri Jan 23, 2004 9:01 am Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
On Mon, 19 Jan 2004 20:52:32 +0100, Fabien LE LEZ
<gramster (AT) gramster (DOT) com> wrote:
| Quote: | On Sun, 18 Jan 2004 11:30:49 +0100, "Marc" <metrica (AT) free (DOT) fr> wrote:
CBase &type1=CType1();
C'est bizarre que ton compilo n'ait pas ralé : "CType1()" crée un
temporaire, et la référence "type1" ne pointe plus sur rien après
cette ligne.
|
Par contre, on peut écrire:
const CBase & type1 = CType1(); // avec const
Un objet temporaire est détruit à la fin de l'expression complète
dans laquelle il apparaît, sauf s'il est lié à une référence
const, auquel cas il sera détruit en même temps que sa référence:
void f() {
const CBase & type1 = CType1(); // création du temporaire
g(type1); // ok, le temporaire existe toujours
} // destruction de la référence et du temporaire
Il n'est cependant pas permis de lier un temporaire à une
référence non const. Voir Stroustrup 10.4.10.
| Quote: | virtual CBase& operator+(const CBase&);
Pas bon non plus : operator+ crée un nouvel objet, renvoyer une
référence est donc une erreur.
|
Ici, il y a effectivement un problème.
--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"
|
|
| Back to top |
|
 |
Andre Heinen Guest
|
Posted: Fri Jan 23, 2004 9:10 am Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
On Tue, 20 Jan 2004 19:06:25 +0100, Fabien LE LEZ
<gramster (AT) gramster (DOT) com> wrote:
| Quote: | On Tue, 20 Jan 2004 14:03:26 +0100, "Marc" <metrica (AT) free (DOT) fr> wrote:
J'avoue que je trouve dommage que l'écriture
CBase &type1=CType1();
ne soit pas acceptée.
Dans quel(s) cas verrais-tu une utilité ?
|
string s1, s2;
....
string s3 = s1 + s2;
// création d'un temporaire, puis recopie dans s3
string & sr = s1 + s2;
// plus rapide: pas de recopie
--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"
|
|
| Back to top |
|
 |
Andre Heinen Guest
|
Posted: Fri Jan 23, 2004 9:13 am Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie |
|
|
On Fri, 23 Jan 2004 10:10:54 +0100, Andre Heinen
<nospam (AT) nospam (DOT) invalid> wrote:
| Quote: | string s1, s2;
...
string s3 = s1 + s2;
// création d'un temporaire, puis recopie dans s3
string & sr = s1 + s2;
// plus rapide: pas de recopie
|
Oups, il y a une faute: il fallait écrire
const string & sr = s1 + s2;
avec const.
--
Andre Heinen
My address is "a dot heinen at europeanlink dot com"
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|