bonjours
je définir un operateur = entre classesmais ça se passe avec mon compilateur!!!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 classe Point{ Point operator = (Point & P) {return P;} }
bonjours
je définir un operateur = entre classesmais ça se passe avec mon compilateur!!!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 classe Point{ Point operator = (Point & P) {return P;} }
"ça se passe avec mon compilateur" ne définit par correctement ton problème.
De plus, ce code est très faux pour un opérateur = de classe. L'idiome Copy-And-Swap est préconisé.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Salut,
Il est déjà beaucoup plus facile de comprendre ce que fait "operator =" lorsque l'on essaye de l'exprimer en bon francais: il s'agit de "l'opératteur d'affectation"
Une fois cette expression faite, tu devrais presque être en mesure, au prix d'un peu de réflexion, de déterminer la manière correcte de le déclarer .
Tu peux aussi décider de retenir la manière de le déclarer par coeur, mais, il faut avouer que cela a beaucoup moins de charme
Allons y donc une fois pour la réflexion, car elle car elle est vraiment intéressante
Nous savons donc qu'il s'agit d'un opérateur d'affectation. Essayons de définir clairement chacun des terme:
- opérateur: pour faire simple, nous pouvons dire qu'il s'agit d'une fonction, même si elle réagit de manière un peu particulière
- affectation: c'est le fait de donner à l'instance courante d'un objet le contenu d'une instance différente
Le fait de parler d'instance courante signifie que nous devons renvoyer... une référence sur un objet, et que l'objet renvoyé doit venir de this.
Pour mémoire, car, pour l'instant nous ne nous inquiétons de la manière correcte de déclarer l'opérateur, cela signifie aussi, étant donné que this est un pointeur qu'il faudra au final renvoyer... ce qui est pointé par this
Il faut aussi s'intéresser à "l'instance différente" que nous voulons assigner à l'instance courante... Elle doit:
- Ne pas être copiée lorsqu'elle est passée comme paramètre à l'opérateur
- Ne pas pouvoir être modifiée par la fonction pour respecter le sacro-saint principe de "const-correctness"
Le (1) implique que l'argument doit être transmis... par référence.
Le (2) implique que l'argument doit être... constant.
au final, nous nous rendons donc compte que l'opérateur d'assignation, que nous désignerons sous le nom de operator= doit renvoyer une référence sur l'objet courent (MonType&) et prendre en argument une référence constante sur l'objet à assigné (MonType const & )
La déclaration correcte sera donc de l'ordre de
Maintenant que la réflexion est faite, tu peux le retenir par coeur
Code : Sélectionner tout - Visualiser dans une fenêtre à part MonType& operator = (MonType const & );
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Il est souvent plus intéressant d'écrire
en fait.
Code : Sélectionner tout - Visualiser dans une fenêtre à part MonType& operator = (MonType);
Boost ftw
Pour rappel, la FAQ contient déjà ce genre de réponse.
Merci de la consulter.
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
En fait, c'est, justement parce que l'on décide de passer l'argument par valeur plutôt que par référence qu'une copie de l'objet passé s'effectue...
Il n'y a donc normalement plus qu'à swapper le contenu de l'argument et de l'objet courant
Or, quand on y regarde de plus près, c'est effectivement ce que conseille l'idiome copy and swap: créer une copie de l'objet passé en paramètre et inverser le contenu de cette copie avec l'objet courant
Il y a peut être des raisons qui font qu'il est plus intéressant de directement demander la copie (louffoque, pourrais tu les donner, s'il y en a), mais, personnellement, j'aime autant "garder la main" sur le moment où je fais des copies de mes objets, et je trouve - à titre personnel - plus cohérent de rester sur le principe d'éviter les copies de classes autant que faire se peut...
Ne serait-ce que parce qu'il reste possible que le constructeur par copie lance une exception et que, en demandant explicitement la copie au sein de l'opérateur d'affectation, je me laisse une chance de récupérer (et de gérer le cas échéans) cette exception
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Ah mais je suis tout à fait d'accord, et dans mon esprit ça c'est toujours passé comme ça, seulement ce n'est pas la première fois que j'entends l'argument de loufoque, et justement j'aimerais bien entendre les dites raisons qui font que c'est plus intéressant.
Edit : en fait c'est ma ma faute, je voulais parlé justement que du swap (non-throwing swap?) .. En me relisant j'ai compris le pourquoi de ton intervention.
Edit 2 : http://en.wikibooks.org/wiki/More_C%.../Copy-and-swap il est question de l'optimisation dû au passage par valeur dans le cas du copy and swap.
"Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu
Il y a peut être des raisons qui font qu'il est plus intéressant de directement demander la copie (louffoque, pourrais tu les donner, s'il y en a)Bien sûr, ça ne marche que si le compilo fait de la NRVO.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <iostream> struct A { A() {} A(const A&) { std::cout << "A::A(const A&)" << std::endl; } }; A make_A() { return A(); } void take_A_1(A a) { } void take_A_2(const A& a) { A a2(a); } int main() { take_A_1(make_A()); // zéro copie take_A_2(make_A()); // une copie }
Boost ftw
Ah, tiens, oui, réellement intéressant...
Mais il reste la bonne question à se poser qui est de savoir si le compilateur utilise la NRVO, et, surtout, si tous les compilateurs actuels ne le supportent pas, quelle politique est la plus intéressante à appliquer
C'est le cas (testé) avec Gcc 4.3.0, et il semble que ce soit le cas pour VC2005...
As-tu une idée en ce qui concerne les autres est-ce, à l'heure actuelle plutôt la règle générale ou plutôt l'exception
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Salut,
J'ai envi de dire que dans le pire des cas (le compilo ne fait pas NRVO - Named Return Value Optimization pour les intimes), tu as le même coût qu'un passage par référence et une variable locale temporaire. Alors que si le compilo supporte la NRVO alors tu gagne une copie. Donc j'aurais tendance à conclure : passe par valeur...
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
Ce qu'on m'avait dit sur les copies, c'était plutôt ça:
Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 class A { private: int a; public: A(int a) : a(a) { } A& operator=(A tmp) { Swap(tmp); return *this; } void Swap(A& other) { std::swap(a, other.a); } }; class B { private: int b; public: B(int b) : b(b) { } B& operator=(B const &src) { B tmp(src); //Copie explicite Swap(tmp); return *this; } void Swap(B& other) { std::swap(b, other.b); } }; int main(void) { { A obj(1); obj = 2; //Passage par valeur: construction directe } { B obj(1); obj = 2; //Construction, puis référence, puis copie explicite } return 0; }
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager