Je veux surcharger l'operator= de B de maniere a ce que:
std::vector<A*> vector;
B b1;
B b2;
vector.push_back (&b1);
vector.push_back (&b2);
(*vector.front ()) = (*vector.back ()); (*)
appelle l'operateur= de la classe B.
1) Si j'ai dans la classe A:
virtual const A & operator=(const A &right)
et dans la classe B:
virtual const B & operator=(const B &right)
Ca marche pas car l'argument de (*) est tjs un A donc il appelle
A::operator=
2) Si je fais:
Dans la classe B:
virtual const A & operator=(const A &right)
Alors je sais que this est un B mais je ne sais rien sur right!!!
Je pourrais dans ce cas faire un dynamic_cast et si c'est pas bon, je
fais un traitement (erreur dans mon cas) et si c'est bon je fais mon
truc mais je me demande si il y a pas un truc (evident??) que j'aurais
manque...
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Christophe Lephay
"blc" a écrit dans le message de news:
Bonjour,
J'ai une classe B qui herite de A.
Je veux surcharger l'operator= de B de maniere a ce que:
std::vector<A*> vector;
B b1; B b2;
vector.push_back (&b1); vector.push_back (&b2);
(*vector.front ()) = (*vector.back ()); (*)
appelle l'operateur= de la classe B.
Il y a peu de chances que celà se produise, vu que ton conteneur ne contient pas des B mais des A *...
1) Si j'ai dans la classe A:
virtual const A & operator=(const A &right)
et dans la classe B:
virtual const B & operator=(const B &right)
Ca marche pas car l'argument de (*) est tjs un A donc il appelle A::operator En plus, je me demande si il n'y aurait pas des restrictions au sujet d'un
operator= polymorphe (et si c'est le cas, c'est surement corrélé au problème que tu évoques)...
2) Si je fais: Dans la classe B:
virtual const A & operator=(const A &right)
Alors je sais que this est un B mais je ne sais rien sur right!!!
Une solution :
class A { public: virtual void assign( const A& ) = 0; // on peut aussi renvoyer un A& };
class B : public A { public: void assign( const A& right ) { // c'est peut etre mieux de déporter ce test dans la classe A, quoiqu'il en soit : assert( dynamic_cast< const B& >( right ) != 0 );
// faire ce que doit faire l'assignation (ou l'affectation) } };
cf l'idiome enveloppe-lettre de Coplien, où il est question d'offrir une sémantique de valeur à des pointeurs. Tu trouveras notemment pas mal d'infos postées par James Kanze dans les archives du groupe...
Chris
"blc" <lecallennec@yahoo.fr> a écrit dans le message de
news:3F3A2B06.8060006@yahoo.fr...
Bonjour,
J'ai une classe B qui herite de A.
Je veux surcharger l'operator= de B de maniere a ce que:
std::vector<A*> vector;
B b1;
B b2;
vector.push_back (&b1);
vector.push_back (&b2);
(*vector.front ()) = (*vector.back ()); (*)
appelle l'operateur= de la classe B.
Il y a peu de chances que celà se produise, vu que ton conteneur ne contient
pas des B mais des A *...
1) Si j'ai dans la classe A:
virtual const A & operator=(const A &right)
et dans la classe B:
virtual const B & operator=(const B &right)
Ca marche pas car l'argument de (*) est tjs un A donc il appelle
A::operator
En plus, je me demande si il n'y aurait pas des restrictions au sujet d'un
operator= polymorphe (et si c'est le cas, c'est surement corrélé au problème
que tu évoques)...
2) Si je fais:
Dans la classe B:
virtual const A & operator=(const A &right)
Alors je sais que this est un B mais je ne sais rien sur right!!!
Une solution :
class A
{
public:
virtual void assign( const A& ) = 0; // on peut aussi renvoyer un A&
};
class B : public A
{
public:
void assign( const A& right )
{
// c'est peut etre mieux de déporter ce test dans la classe A, quoiqu'il
en soit :
assert( dynamic_cast< const B& >( right ) != 0 );
// faire ce que doit faire l'assignation (ou l'affectation)
}
};
cf l'idiome enveloppe-lettre de Coplien, où il est question d'offrir une
sémantique de valeur à des pointeurs. Tu trouveras notemment pas mal d'infos
postées par James Kanze dans les archives du groupe...
Je veux surcharger l'operator= de B de maniere a ce que:
std::vector<A*> vector;
B b1; B b2;
vector.push_back (&b1); vector.push_back (&b2);
(*vector.front ()) = (*vector.back ()); (*)
appelle l'operateur= de la classe B.
Il y a peu de chances que celà se produise, vu que ton conteneur ne contient pas des B mais des A *...
1) Si j'ai dans la classe A:
virtual const A & operator=(const A &right)
et dans la classe B:
virtual const B & operator=(const B &right)
Ca marche pas car l'argument de (*) est tjs un A donc il appelle A::operator En plus, je me demande si il n'y aurait pas des restrictions au sujet d'un
operator= polymorphe (et si c'est le cas, c'est surement corrélé au problème que tu évoques)...
2) Si je fais: Dans la classe B:
virtual const A & operator=(const A &right)
Alors je sais que this est un B mais je ne sais rien sur right!!!
Une solution :
class A { public: virtual void assign( const A& ) = 0; // on peut aussi renvoyer un A& };
class B : public A { public: void assign( const A& right ) { // c'est peut etre mieux de déporter ce test dans la classe A, quoiqu'il en soit : assert( dynamic_cast< const B& >( right ) != 0 );
// faire ce que doit faire l'assignation (ou l'affectation) } };
cf l'idiome enveloppe-lettre de Coplien, où il est question d'offrir une sémantique de valeur à des pointeurs. Tu trouveras notemment pas mal d'infos postées par James Kanze dans les archives du groupe...
Chris
Christophe Lephay
"Loïc Joly" a écrit dans le message de news:bhe5na$8ec$
Ca m'a l'ai assez proche de l'idiome lettre-enveloppe (que je ne connais pas bien), mais il suffit d'écrire cette classe une fois pour toutes.
C'est vrai que les deux sont assez proches, la différence principale me semblant être qu'on n'a pas à déréférencer pour accéder à la valeur avec l'idiome enveloppe-lettre.
Dans l'idiome enveloppe-lettre tel que je me l'imagine, la classe enveloppe est une classe de base pour la (les) classe(s) lettre(s). Je ne sais pas si c'est une propriété intrinsèque de l'idiome ou une variante, auquel cas c'est la variante que j'ai retenue du bouquin de Coplien.
class lettre : public enveloppe { ... void fonction() { /* quoique ce soit */ } };
En fait, avec l'idiome enveloppe-lettre, on applique la fonction membre sur l'enveloppe, qui la répercute sur la lettre, alors qu'un pointeur intelligent t'oblige à déréférencer pour appeler la fonction membre (et reste donc un pointeur, même si il et intelligent).
Comme le soulignait james dans un post pas si lointain, le problème est aussi souvent résolu par une classe proxy (dans laquelle la classe manipulée n'a pas à appartenir à la même hiérarchie que la classe masquée), qui répercute aussi automatiquement l'appel de la fonction membre sur le pointeur masqué.
Une différence évidente entre l'idiome enveloppe-lettre et l'idiome proxy, c'est que c'est la classe gérante qui impose la sémantique(*) à la classe gérée pour le premier, alors que c'est le contraire avec le second(**). L'inconvénient principal de la classe enveloppe-lettre est de ne pas pouvoir être utilisé à postériori (inapplicable en l'état sur des classes déjà existantes).
Dans le cas du posteur initial, quoiqu'il en soit, les trois solutions me semblent valides, remplaçant chacune l'affectation de pointeurs par une affectation d'objets.
(*) la classe enveloppe ne peut bien évidemment pas être une classe abstraite si l'objectif est de passer par elle pour avoir une sémantique de valeurs, d'objets donc. C'est pourquoi j'ai préféré parler de sémantique plutôt que d'interface (**) on pourrait presque dire que la classe gérée n'impose rien à la classe gérante dans la mesure où il n'existe aucune relation d'héritage entre les deux. D'ailleurs, lorsque les interfaces de la classe proxy et de la classe "proxied" diffère, ça devient un pont et le compilateur continue sa route en baillant à s'en décrocher la machoire.
Chris
"Loïc Joly" <loic.actarus.joly@wanadoo.fr> a écrit dans le message de
news:bhe5na$8ec$1@news-reader3.wanadoo.fr...
Ca m'a l'ai assez proche de l'idiome lettre-enveloppe (que je ne connais
pas bien), mais il suffit d'écrire cette classe une fois pour toutes.
C'est vrai que les deux sont assez proches, la différence principale me
semblant être qu'on n'a pas à déréférencer pour accéder à la valeur avec
l'idiome enveloppe-lettre.
Dans l'idiome enveloppe-lettre tel que je me l'imagine, la classe enveloppe
est une classe de base pour la (les) classe(s) lettre(s). Je ne sais pas si
c'est une propriété intrinsèque de l'idiome ou une variante, auquel cas
c'est la variante que j'ai retenue du bouquin de Coplien.
class lettre : public enveloppe
{
...
void fonction() { /* quoique ce soit */ }
};
En fait, avec l'idiome enveloppe-lettre, on applique la fonction membre sur
l'enveloppe, qui la répercute sur la lettre, alors qu'un pointeur
intelligent t'oblige à déréférencer pour appeler la fonction membre (et
reste donc un pointeur, même si il et intelligent).
Comme le soulignait james dans un post pas si lointain, le problème est
aussi souvent résolu par une classe proxy (dans laquelle la classe manipulée
n'a pas à appartenir à la même hiérarchie que la classe masquée), qui
répercute aussi automatiquement l'appel de la fonction membre sur le
pointeur masqué.
Une différence évidente entre l'idiome enveloppe-lettre et l'idiome proxy,
c'est que c'est la classe gérante qui impose la sémantique(*) à la classe
gérée pour le premier, alors que c'est le contraire avec le second(**).
L'inconvénient principal de la classe enveloppe-lettre est de ne pas pouvoir
être utilisé à postériori (inapplicable en l'état sur des classes déjà
existantes).
Dans le cas du posteur initial, quoiqu'il en soit, les trois solutions me
semblent valides, remplaçant chacune l'affectation de pointeurs par une
affectation d'objets.
(*) la classe enveloppe ne peut bien évidemment pas être une classe
abstraite si l'objectif est de passer par elle pour avoir une sémantique de
valeurs, d'objets donc. C'est pourquoi j'ai préféré parler de sémantique
plutôt que d'interface
(**) on pourrait presque dire que la classe gérée n'impose rien à la classe
gérante dans la mesure où il n'existe aucune relation d'héritage entre les
deux. D'ailleurs, lorsque les interfaces de la classe proxy et de la classe
"proxied" diffère, ça devient un pont et le compilateur continue sa route en
baillant à s'en décrocher la machoire.
Ca m'a l'ai assez proche de l'idiome lettre-enveloppe (que je ne connais pas bien), mais il suffit d'écrire cette classe une fois pour toutes.
C'est vrai que les deux sont assez proches, la différence principale me semblant être qu'on n'a pas à déréférencer pour accéder à la valeur avec l'idiome enveloppe-lettre.
Dans l'idiome enveloppe-lettre tel que je me l'imagine, la classe enveloppe est une classe de base pour la (les) classe(s) lettre(s). Je ne sais pas si c'est une propriété intrinsèque de l'idiome ou une variante, auquel cas c'est la variante que j'ai retenue du bouquin de Coplien.
class lettre : public enveloppe { ... void fonction() { /* quoique ce soit */ } };
En fait, avec l'idiome enveloppe-lettre, on applique la fonction membre sur l'enveloppe, qui la répercute sur la lettre, alors qu'un pointeur intelligent t'oblige à déréférencer pour appeler la fonction membre (et reste donc un pointeur, même si il et intelligent).
Comme le soulignait james dans un post pas si lointain, le problème est aussi souvent résolu par une classe proxy (dans laquelle la classe manipulée n'a pas à appartenir à la même hiérarchie que la classe masquée), qui répercute aussi automatiquement l'appel de la fonction membre sur le pointeur masqué.
Une différence évidente entre l'idiome enveloppe-lettre et l'idiome proxy, c'est que c'est la classe gérante qui impose la sémantique(*) à la classe gérée pour le premier, alors que c'est le contraire avec le second(**). L'inconvénient principal de la classe enveloppe-lettre est de ne pas pouvoir être utilisé à postériori (inapplicable en l'état sur des classes déjà existantes).
Dans le cas du posteur initial, quoiqu'il en soit, les trois solutions me semblent valides, remplaçant chacune l'affectation de pointeurs par une affectation d'objets.
(*) la classe enveloppe ne peut bien évidemment pas être une classe abstraite si l'objectif est de passer par elle pour avoir une sémantique de valeurs, d'objets donc. C'est pourquoi j'ai préféré parler de sémantique plutôt que d'interface (**) on pourrait presque dire que la classe gérée n'impose rien à la classe gérante dans la mesure où il n'existe aucune relation d'héritage entre les deux. D'ailleurs, lorsque les interfaces de la classe proxy et de la classe "proxied" diffère, ça devient un pont et le compilateur continue sa route en baillant à s'en décrocher la machoire.
Chris
blc
Merci a tous pour vos reponses. J'ai finalement fait une methode assign..
Benoit
Merci a tous pour vos reponses. J'ai finalement fait une methode assign..