Opérateurs d’affectation

L’affectation =, et ses dérivées +=, *=, etc., sont des opérateurs binaires. L’affectation 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. C’est 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 l’on souhaite interdire de telles écritures.

Exercice 7.5

Dans les anciennes versions de C++, l’affectation prédéfinie était une copie en bloc d’un objet dans l’autre. Pouvez-vous donner un exemple où le comportement de la nouvelle version diffère de l’ancienne ? 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 l’opérateur d’affectation, mais pour m1, c’est le constructeur de copie (qui existe toujours, voir chapitre 6) qui est appelé. Cette séquence résulte donc (nonobstant le fait qu’on ne peut appeler explicitement un constructeur) en :

matrice m1.matrice::matrice(m2);    // constructeurm3.operator=(m2);            // affectation

De ce fait, lorsqu’un opérateur d’affectation 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 l’on 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 n’existe aucun moyen direct de « dédéfinir » l’affectation ou la construction par copie, qui sont toujours fournies par défaut lorsqu’on 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 l’une ou l’autre provoquera une erreur d’édition de liens ; c’est 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 d’une 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 l’addition, et c’est sur cette copie que l’on ajoute le deuxième argument (voir la fin du chapitre).

Précédent Précédent Sommaire Sommaire Suivant Suivant