OVH Cloud OVH Cloud

operator =

10 réponses
Avatar
emmanuel.rauturier
Salut, j'ai un petit problème de C++

J'ai une classe avec un opérateur =, et deux autres classes (_b et _c)
qui dérivent de cette classe. J'essaie de faire _b = _b + _c, mais ca
ne marche pas. Dans l'operateur =, c'est bon (je le sais après avoir
debuggé), mais quand je retourne au contexte appelant, mon objet ne
conserve pas les données.

Quelqu'un peut'il m'aider ? Pleeeeeeease....

10 réponses

Avatar
Jean-Marc Bourguet
(emmanuel) writes:

Salut, j'ai un petit problème de C++

J'ai une classe avec un opérateur =, et deux autres classes (_b et _c)
qui dérivent de cette classe. J'essaie de faire _b = _b + _c, mais ca
ne marche pas. Dans l'operateur =, c'est bon (je le sais après avoir
debuggé), mais quand je retourne au contexte appelant, mon objet ne
conserve pas les données.

Quelqu'un peut'il m'aider ? Pleeeeeeease....


Peux-tu donner un exemple complet, ce que tu obtiens et ce à quoi tu
t'attendais?

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
emmanuel.rauturier
Jean-Marc Bourguet wrote in message news:...
(emmanuel) writes:

Salut, j'ai un petit problème de C++

J'ai une classe avec un opérateur =, et deux autres classes (_b et _c)
qui dérivent de cette classe. J'essaie de faire _b = _b + _c, mais ca
ne marche pas. Dans l'operateur =, c'est bon (je le sais après avoir
debuggé), mais quand je retourne au contexte appelant, mon objet ne
conserve pas les données.

Quelqu'un peut'il m'aider ? Pleeeeeeease....


Peux-tu donner un exemple complet, ce que tu obtiens et ce à quoi tu
t'attendais?

A+


En gros c'était comme ceci :
class A {
...
A operator+( const A & );
void operator=(const A & );
};

B : public A {
};

C : public A {
};

A A::operator+(const A &AToAdd)
{
A toRet;

... // init this = this + AToAdd

return toRet;
}

void A::operator=(const A& AToCopy)
{
... // copy this = AToCopy
}


B _b;
C _c;

_c = _c + _b;

// Ici j'avais mon problème ; le _c final ne changeait pas d'état.

Alors en fait, j'ai plus ou moins trouvé une solution à mon problème,
mais sans vraiment comprendre ce qui se passe ; il manquait le "&"
dans A &A

A &A::operator+(const A &AToAdd)

J'ai surtout utilisé le "&" en C pour avoir l'adresse d'un objet. J'ai
plus ou moins compris le const ... & (qui pour moi reste une facilité
d'utilisation/substitution par rapport au passage d'adresse)(me
trompe-je ???), mais là dans ce contexte, je comprends pas du tout.
Surtout que je ne vois toujours pas très bien mon problème. Mon
operateur + utilise une variable locale, mais n'est-elle pas sensé
être recopiée en mémoire dans un nouvel objet quand on fait le return
? Et surtout je ne vois pas bien pourquoi l'opérateur = ne fonctionne
pas. Et que fait exactement ce %*$# "&" ?


Avatar
Guillaume Gourdin
Alors en fait, j'ai plus ou moins trouvé une solution à mon problème,
mais sans vraiment comprendre ce qui se passe ; il manquait le "&"
dans A &A

A &A::operator+(const A &AToAdd)


Eeuh, non, normalement, l'operateur + ne renvoit pas une référence. Il
devrait être de la forme :

A A::operator+(const A &AToAdd)
{
A Result;
// dans ton résult, tu mets le résultat de l'addition de this et de AToAdd
return ( Result);
}

Avatar
Vianney Lançon
Le 26 Aug 2003 00:50:06 -0700, dans fr.comp.lang.c++,
emmanuel a dit :
Jean-Marc Bourguet wrote in message news:...
(emmanuel) writes:

Salut, j'ai un petit problème de C++

J'ai une classe avec un opérateur =, et deux autres classes (_b et _c)
qui dérivent de cette classe. J'essaie de faire _b = _b + _c, mais ca
ne marche pas. Dans l'operateur =, c'est bon (je le sais après avoir
debuggé), mais quand je retourne au contexte appelant, mon objet ne
conserve pas les données.

Quelqu'un peut'il m'aider ? Pleeeeeeease....


Peux-tu donner un exemple complet, ce que tu obtiens et ce à quoi tu
t'attendais?

A+


En gros c'était comme ceci :
class A {
...
A operator+( const A & );
void operator=(const A & );
};


Tu semble avoir oublié de definir le constructeur de copy?
A::A(const A&)§?

A tu pense à mettre tes constructeur à 1 paramètre en explicit pour
éviter les convertions indésirable?

Je te conseille de définir la fonction membre +=
A& A::operator+=(const A& a_)

L'operator + ne doit pas être une fonction membre.
Cella permet de definir des a_ + c_
const A operator+(const A& lhs_, const B& rhs_)
{
A ret(lhs_);
ret += rhs_;
return ret;
}

L'operator = doit retourner une reférence.
Cella permet de faire c1 = c2 = c3;
A& A::operator=( const A& other );

-
Vianney LANÇON
radix omnia malorum prematurae optimisatia est
-- Donald Knuth



Avatar
Laurent DELEPINE
emmanuel wrote:

Quelqu'un peut'il m'aider ? Pleeeeeeease....


Peux-tu donner un exemple complet, ce que tu obtiens et ce à quoi tu
t'attendais?

A+



En gros c'était comme ceci :


En detail ca donne quoi.

Si on ne sait pas ce que font tes classes en interne on va avoir du mal.

Je peux signaler une erreur flagrante cependant :

void A::operator=(const A & );


Le prototype exact est A& operator= (const A &);
Ca permet d'avoir des ecriture du style X = Y = Z = ...
Mais l'origine de ton probleme n'est pas la.

Le code "complet" de operator = est le suivant

A& operator= (const A& a)
{
if (this != &a)
{
// Affectation
}
return *this;
}

Le if permet de gerer le cas X = X
le return permet le chainage des



A+

LD



Avatar
Loïc Joly
Laurent DELEPINE wrote:
Le code "complet" de operator = est le suivant

A& operator= (const A& a)
{
if (this != &a)
{
// Affectation
}
return *this;
}

Le if permet de gerer le cas X = X
le return permet le chainage des
Ce code n'est plus vraiment en vogue depuis que les gens essayent de

faire du code exception-safe. Je dirait que la nouvelle écriture par
défaut de cet opérateur ressemble plus à :

A& operator= (A const &a)
{
A temp(a);
swap(temp);
}

Avec A::swap une fonction ne lançant pas d'exception et échangeant les
valeurs de toutes les variables membre (probablement en utilisant
std::swap pour les types de base).

--
Loïc

Avatar
kanze
Laurent DELEPINE wrote in message
news:<3f4b99c0$0$245$...
emmanuel wrote:

Quelqu'un peut'il m'aider ? Pleeeeeeease....


Peux-tu donner un exemple complet, ce que tu obtiens et ce à quoi tu
t'attendais?


En gros c'était comme ceci :


En detail ca donne quoi.

Si on ne sait pas ce que font tes classes en interne on va avoir du
mal.

Je peux signaler une erreur flagrante cependant :

void A::operator=(const A & );


Le prototype exact est A& operator= (const A &);


Le prototype exact, c'est ce que le programmeur veut. La seule
contrainte, c'est qu'il soit membre non-statique, et qu'il prend
exactement un paramètre. En plus, si le programmeur n'a pas déclaré un
operator= non-templaté dont le type du paramètre est T, T&, T const&, T
volatile& ou T const volatile&, le compilateur déclare un soit avec la
signature « T& T::operator=( T const& ) », soit avec la signature
« T& T::operator=( T& ) ».

Dans la pratique, selon qui on démande, il est bon ton que le type de
retour soit ou bien T&, ou bien T const&, dans le cas général. Mais il y
a aussi des exceptions : dans un proxy, il n'est pas rare que le type de
rétour soit void, par exemple (ni, d'ailleur, que l'operator= soit une
fonction const).

Ca permet d'avoir des ecriture du style X = Y = Z = ...
Mais l'origine de ton probleme n'est pas la.

Le code "complet" de operator = est le suivant

A& operator= (const A& a)
{
if (this != &a)
{
// Affectation
}
return *this;
}

Le if permet de gerer le cas X = X le return permet le chainage des
La nécessité d'un test pour l'auto-affectation est en général une

indication d'une erreur, et de tel test est rarissime dans du bon code.

--
James Kanze GABI Software mailto:
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




Avatar
Laurent DELEPINE
Loïc Joly wrote:

A& operator= (A const &a)
{
A temp(a);
swap(temp);
}


Merci je note ca dans mes pappier, ca va me servir bientot (dans
quelques minutes au plus).

Avatar
fbinard
Salut, 2 ou 3 réponses:

Ton opérateur + devrait ressembler à
-----------------------------------------------
A& A::operator+(const A& AToAdd){
.....

A* Res = new A(....);
return *Res;
}
------------------------------------------------
--> A* Res = new A(...) crée un pointeur à un objet de type A. Mais comme
c'est le contenu du pointeur (et non l'adresse) que tu veux que ta fonction
rende, ton type de retour doit être doit être un alias(référence). Alors
pourquoi pas:
----------------------------------------
A A::operator+(const A& AToAdd){
.....

A* Res = new A(....);
return *Res;
}
ou même:
------------------------------------------
A A::operator+(const A& AToAdd){
.....

A Res (....);
return Res;
}
----------------------------------------
?parce que si tu fais ca, tu doit faire un appel de constructeur copie (que
tu n'as pas l'air d'avoir implémenté). L'appel se fait au niveau de la
commande `return`.
Ton objet ne sait pas ce que ca veut dire d'avoir une valeur. il ne sait pas
comment se copier sur le stack, ce qui se fait automatiquement lors d'un
appel return.
Si le 1er cas marchait, tu perdrais la mémoire alloué en +.

Finalement, ceci ne marche pas/est très dangereux:

-----------------------------------------------
A& A::operator+(const A& AToAdd){
.....

A Res (....);
return Res;
}
------------------------------------------------
Parce que Res ne t'appartient + en sortant de ta fonction, et la mémoire
retourne au system. Tu retournerai une référence à 1 truc sur lequel tu n'as
+ aucun controle.

2. petit truc:
tu peut même implémenter ton opérateur = de la manière suivante:
----------------------------------------------
A& A::operator=(const A& AToEqual){
.....

return *this;
}
---------------------------------------------------
comme ca, tu peux faire des trucs du genre:
A1 = A2 = A3;

3. je te conseille fortement de toujours faire un constructeur copie:
____________________________________

A::A(const A& AtoCopy){
...
}

non seulement ta première form de `+` devrait se mettre à marcher, mais en
générale, ca t'éviteras pas mal de probléme sur ta gestion de mémoire parce
que tu pourra controler la manière dont les copies de tes objets sont faite
lorsqu'ils sont passés à ou reviennent de tes fonctions. C'à devient
vraiment important quand les private/protected de tes fonctions sont des
pointeurs.


______________________________






En gros c'était comme ceci :
class A {
...
A operator+( const A & );
void operator=(const A & );
};

B : public A {
};

C : public A {
};

A A::operator+(const A &AToAdd)
{
A toRet;

... // init this = this + AToAdd

return toRet;
}

void A::operator=(const A& AToCopy)
{
... // copy this = AToCopy
}


B _b;
C _c;

_c = _c + _b;

// Ici j'avais mon problème ; le _c final ne changeait pas d'état.

Alors en fait, j'ai plus ou moins trouvé une solution à mon problème,
mais sans vraiment comprendre ce qui se passe ; il manquait le "&"
dans A &A

A &A::operator+(const A &AToAdd)

J'ai surtout utilisé le "&" en C pour avoir l'adresse d'un objet. J'ai
plus ou moins compris le const ... & (qui pour moi reste une facilité
d'utilisation/substitution par rapport au passage d'adresse)(me
trompe-je ???), mais là dans ce contexte, je comprends pas du tout.
Surtout que je ne vois toujours pas très bien mon problème. Mon
operateur + utilise une variable locale, mais n'est-elle pas sensé
être recopiée en mémoire dans un nouvel objet quand on fait le return
? Et surtout je ne vois pas bien pourquoi l'opérateur = ne fonctionne
pas. Et que fait exactement ce %*$# "&" ?


Avatar
kanze
"fbinard" wrote in message
news:<Zsz3b.22875$...
Salut, 2 ou 3 réponses:

Ton opérateur + devrait ressembler à
-----------------------------------------------
A& A::operator+(const A& AToAdd){
.....

A* Res = new A(....);
return *Res;
}
------------------------------------------------

--> A* Res = new A(...) crée un pointeur à un objet de type A. Mais
comme c'est le contenu du pointeur (et non l'adresse) que tu veux que
ta fonction rende, ton type de retour doit être doit être un
alias(référence). Alors pourquoi pas:


Surtout, le problème est qui fait le delete. Si l'utilisateur fait :

A& result = unA.add( unAutreA ) ;
// ...
delete &result ;

Ça pourrait marcher, mais il faut l'avouer, ce n'est pas l'utilisation
attendue pour l'opérateur +.

----------------------------------------
A A::operator+(const A& AToAdd){
.....

A* Res = new A(....);
return *Res;
}


Ce qui est encore pire, parce que dans ce cas, c'est complètement
impossible à libérer la mémoire.

ou même:
------------------------------------------
A A::operator+(const A& AToAdd){
.....

A Res (....);
return Res;
}
----------------------------------------


C'est la solution canonique (sauf qu'en général, l'opérateur + n'est pas
un membre).

?parce que si tu fais ca, tu doit faire un appel de constructeur copie
(que tu n'as pas l'air d'avoir implémenté). L'appel se fait au niveau
de la commande `return`.


En fait, il faut que le constructeur de copie soit accessible. En
revanche, le compilateur n'est pas obligé à s'en servir ; il peut fuser
la variable Res avec l'objet renvoyé.

Ton objet ne sait pas ce que ca veut dire d'avoir une valeur. il ne
sait pas comment se copier sur le stack, ce qui se fait
automatiquement lors d'un appel return. Si le 1er cas marchait, tu
perdrais la mémoire alloué en +.

Finalement, ceci ne marche pas/est très dangereux:

-----------------------------------------------
A& A::operator+(const A& AToAdd){
.....

A Res (....);
return Res;
}
------------------------------------------------
Parce que Res ne t'appartient + en sortant de ta fonction, et la
mémoire retourne au system. Tu retournerai une référence à 1 truc sur
lequel tu n'as + aucun controle.


Sur un truc qui n'existe plus, en tout cas. C'est une chose à ne jamais
faire.

--
James Kanze GABI Software mailto:
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