Copie d’objets
Rappel : passage par valeur, par référence
Passage par valeur
void f(int i) { i = 10; cout << "f : " << i << endl; } int main() { int e = 0; f(e); cout << "main : " << e << endl; return EXIT_SUCCESS; }
f : 10
main : 0
Passage par référence
void g(int& i) { i = 10; cout << "g : " << i << endl; } int main() { int e = 0; g(e); cout << "main : " << e << endl; return EXIT_SUCCESS; }
g : 10
main : 10
Passage d’objets par valeur, par référence
Passage par valeur
void f(Complexe z) { z.set_real_imag(2, 3); cout << "f : "; z.affiche(); } int main() { Complexe p(1, 0.5); f(p); cout << "main : "; p.affiche(); return EXIT_SUCCESS; }
f : (2 + 3i)
main : (1 + 0.5i)
Passage par référence
void g(Complexe& z) { z.set_real_imag(2, 3); cout << "g : "; z.affiche(); } int main() { Complexe p(1, 0.5); g(p); cout << "main : "; p.affiche(); return EXIT_SUCCESS; }
g : (2 + 3i)
main : (2 + 3i)
Passage d’objets par valeur, par référence
Passage par valeur
void f(Complexe z) { cout << "Le complexe vaut "; z.affiche(); } int main() { Complexe p(1, 0.5); f(p); return EXIT_SUCCESS; }
L’objet est copié
Passage par référence constante
void g(const Complexe& z) { cout << "Le complexe vaut "; z.affiche(); } int main() { Complexe p(1, 0.5); g(p); return EXIT_SUCCESS; }
Une copie inutile est évitée
Objets constants
Le mot-clé const
interdit la modification de l’objet auquel il s’applique.
const int i = 42; i = 3; // erreur de compilation
void f(const Complexe& z) { z.affiche(); // possible z.set_real_imag(1, 2); // impossible }
Le compilateur doit savoir quelles méthodes modifient l’objet.
Méthodes et “const
-correctness”
Le prototype d’une méthode doit se terminer par const
si celle-ci ne
modifie pas l’objet :
class Complexe { public: ... void affiche() const; void set_real_imag(double real, double imag); ... };
- Par défaut les méthodes peuvent modifier l’objet.
- En cas d’oubli de
const
, la méthode ne peut donc pas être utilisée sur des objets constants.
Copier un objet
La copie est la création d’un nouvel objet ayant la même valeur qu’un objet existant.
class Point { public: ... Point(const Point& other); ... private: int m_x; int m_y; };
Copier un objet : le constructeur de copie
Exemple de définition d’un constructeur de copie :
#include "Point.h" #include <iostream> using namespace std; Point::Point(const Point& other) : m_x(other.m_x), m_y(other.m_y) { cout << "copie de Point" << endl; }
- En l’absence de constructeur de copie le compilateur en génère un automatiquement : il copie une à une les valeurs des membres.
- Lorsqu’une classe gère de la mémoire allouée dynamiquement, un constructeur de copie est donc indispensable.
Exemple de copie inévitable
Parfois on ne peut pas éviter de copier un objet :
Complexe f(); int main() { Complexe z = f(); z.affiche(); return EXIT_SUCCESS; }
La valeur de retour de f
est copiée dans le nouvel objet z
.
Exemple de copie évitable
Mais on peut souvent éviter des copies inutiles :
Copie inutile
Complexe f() { Complexe z(1, 2); return z; }
La variable locale z
est copiée dans un objet anonyme retourné par la
fonction.
Sans copie inutile
Complexe f() { return Complexe(1, 2); }
Il n’y a plus de variable locale. L’objet anonyme est construit directement.