C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Rédéfinition de l'opérateur + dans toute une hierarchie de c

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Marc
Guest





PostPosted: Sun Jan 18, 2004 10:30 am    Post subject: Rédéfinition de l'opérateur + dans toute une hierarchie de c Reply with quote



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





PostPosted: Mon Jan 19, 2004 7:52 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote



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
__|__
Quote:
|
A B


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





PostPosted: Mon Jan 19, 2004 11:13 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote



"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





PostPosted: Tue Jan 20, 2004 7:49 am    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

"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.

Quote:
...
};

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





PostPosted: Tue Jan 20, 2004 1:03 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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





PostPosted: Tue Jan 20, 2004 1:10 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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





PostPosted: Tue Jan 20, 2004 6:06 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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





PostPosted: Tue Jan 20, 2004 8:00 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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





PostPosted: Tue Jan 20, 2004 8:47 pm    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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 ! Smile

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





PostPosted: Fri Jan 23, 2004 5:14 am    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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 ?

Quote:
Marc

Gourgouilloult du Clapotis


Back to top
Gourgouilloult
Guest





PostPosted: Fri Jan 23, 2004 5:18 am    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

Quote:
CBase& CType1::operator+(const CBase& x) const

Oui bon, en omettant la question du retour par référence, on va dire. Wink
(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





PostPosted: Fri Jan 23, 2004 9:01 am    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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





PostPosted: Fri Jan 23, 2004 9:10 am    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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





PostPosted: Fri Jan 23, 2004 9:13 am    Post subject: Re: Rédéfinition de l'opérateur + dans toute une hierarchie Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.