On peut définir un constructeur
particulier qui permet de copier un objet de la classe;
un tel constructeur pour la classe X
aura la forme
X::X(X&)
ou X::(const X&)
(et éventuellement d'autres
arguments). Cet opérateur de copie permet, par exemple,
de réaliser des
copies
profondes :
// chaines avec copie profonde class chaine{ public: chaine(const char *s){ lg=strlen(s); ch= new char [lg +1]; assert(ch != 0); ch=strcpy(ch,s); }; // ... chaine(const chaine&); // ... ~chaine(){delete [] ch;} private: char *ch; int lg; }; chaine::chaine(const chaine &c){ lg=c.lg; ch= new char [lg+1]; assert(ch != 0); ch=strcpy(ch,c); }
Si ce constructeur de copie n'était pas défini, le
constructeur par défaut ferait une copie de chaque donnée
membre, et la donnée membre ch
du nouvel
objet
pointerait sur la même adresse que l'ancien (ce qui
pourrait poser des problèmes si un des deux objets
libérait la mémoire associée...).
Il ne faut pas confondre la copie et l'affectation:
X a; X a=b; // constructeur de copie a=b; // affectation
Quand un objet d'une classe est initialisé par un autre objet de la classe, le constructeur de copie est appelé. Si aucun constructeur de copie n'a été défini par l'utilisateur de la classe, on utilise un constructeur de copie par défaut qui réalise une copie membre à membre.
Plus généralement, le constructeur de copie est appelé par le compilateur chaque fois que l'on doit initialiser un objet de la classe par un autre objet de la classe; par exemple:
X a=b;
void print(chaine); //... chaine ch; print(ch); // appel de chaine::chaine(ch)
chaine pos(const chaine&,int); //... ch=pos(ch1,2); // appel de chaine::chaine(chaine&) // sur le résultat de pos
class X{ //... public: X(const &X);//... }; X a; // X::X() X a=b; // X::X(a) void fv(X x){/*...*/} void fr(X& x){/*...*/} X gv(int i){/*...*/} X& gr(int i){/*...*/} void f(){ X c; //... fv(a); // fv(X::X(a)) fr(a); // passage par reference c=gv(2); // appel de X::X(X&) pour le resultat gr(1)=c; // pas d'appel de X::X(X&) }
Comme on peut le remarquer, le constructeur de copie ne concerne pas les passages par références (ni, bien sûr, les pointeurs) car ce type de passage ne provoque pas la création d'une copie locale de l'objet. Par contre dans le passage de références ou de pointeur une conversion de pointeurs peut avoir lieu et permettra la liaison dynamique.