Laffectation =
, et ses dérivées +=
, *=
, etc., sont des opérateurs binaires. Laffectation est prédéfinie pour toutes les classes, et représente alors une copie terme à terme des membres de la classe.
Il est parfaitement possible de la redéfinir. Cest spécialement utile pour les classes utilisant des membres pointeurs. Par exemple, pour la classe matrice :
class matrice { double *tab; // liste des éléments à la suite unsigned lgn, col; // nb de lignes et colonnes public: // ... matrice& operator=(matrice& m) { lgn = m.lgn; col = m.col; tab = new double[lgn*col]; return *this; } };
En général, on retourne type&
comme résultat, afin de permettre des écritures du type :
matrice m1, m2;m1 = m2 = m1 + m2;
Toutefois, on peut aussi déclarer un résultat void
si lon souhaite interdire de telles écritures.
Exercice 7.5 | Dans les anciennes versions de C++, laffectation prédéfinie était une copie en bloc dun objet dans lautre. Pouvez-vous donner un exemple où le comportement de la nouvelle version diffère de lancienne ? Quel comportement est préférable selon vous ? |
Voir solution |
Il est très important de différencier les deux écritures suivantes :
matrice m1 = m2;m3 = m2;
Pour m3
, le compilateur appelle lopérateur daffectation, mais pour m1
, cest le constructeur de copie (qui existe toujours, voir chapitre 6) qui est appelé. Cette séquence résulte donc (nonobstant le fait quon ne peut appeler explicitement un constructeur) en :
matrice m1.matrice::matrice(m2); // constructeurm3.operator=(m2); // affectation
De ce fait, lorsquun opérateur daffectation est défini, on écrira généralement le constructeur de copie ainsi :
inline matrice::matrice(matrice& m)// constructeur de copie{ *this = m; }
sauf si lon souhaite des effets particuliers et différents (à vos risques et périls).
Dans certains cas, on souhaite rendre impossible une affectation dans une classe, ou encore une copie par construction. Cependant il nexiste aucun moyen direct de « dédéfinir » laffectation ou la construction par copie, qui sont toujours fournies par défaut lorsquon ne les redéfinit pas. Un moyen indirect consiste à déclarer les méthodes correspondantes, mais sans en donner de définition (aucune implantation). Dans ce cas, tout appel de lune ou lautre provoquera une erreur dédition de liens ; cest la méthode utilisée pour certaines classes de flots (voir chapitre 9). Une autre possiblité est de déclarer ces méthodes dans la partie privée dune classe ; dans ce cas, le compilateur refusera les appels de copie, mais pas dans les fonctions amies ni les méthodes.
Les affectations-opérations comme +=
ne sont jamais prédéfinies pour une classe, et jamais interprétées comme des raccourcis décriture pour x = x + y
. En conséquence, on définira de même :
matrice& operator+=(matrice& m){ return *this = *this + m; }
Dans certains cas, il sera peut-être rentable de faire le contraire :
matrice& operator +=(matrice& m){ // ... faire une addition sur place}matrice& operator+(matrice m1, matrice& m2){ return m1 += m2;}
Noter que, comme dans ce dernier cas m1
a été passé par valeur et non par référence comme m2
, un constructeur de copie est appelé au moment de laddition, et cest sur cette copie que lon ajoute le deuxième argument (voir la fin du chapitre).
Précédent | Sommaire | Suivant |