Il n'existe qu'un destructeur par classe, mais il peut exister plusieurs
constructeurs. Ceux-ci ont alors des arguments différents, mais sont
formatés de la même façon (même nom, pas de retour). Par exemple:
class Tableau { double* tab; int n; public: Tableau(){ n = 0; } Tableau(int a){ n = a; tab = new double[a]; } // autres champs et fonctions membres, destructeur };
Au moment de la déclaration d'un objet de cette classe, on a alors le choix
entre les deux constructeurs:
Tableau A; // appelle le constructeur sans argument // et initialise donc A.n à 0 Tableau B(5); // appelle le constructeur avec un argument de type int // et alloue donc un tableau de taille 5
Il existe un constructeur particulier, le constructeur par copie. Celui-ci
prend comme argument une référence (éventuellement constante) sur un objet de la même
classe. C'est ce constructeur qui est appelé lorsque l'on passe à un argument
à une fonction et que celle-ci recopie automatiquement cet argument dans
une variable locale à elle. Par défaut, ce constructeur recopie un à un les
champs de l'objet en argument dans le nouveau. Dans notre cas, il
recopierait la valeur du champ n
ainsi que la valeur du pointeur
tab
, c-à-d qu'il créérait un nouveau pointeur vers le même tableau
que précédemment. Si l'on préfère que le nouvel objet ne partage pas le
même tableau, mais qu'un nouveau tableau soit alloué et que l'on recopie
les différentes cases de l'ancien dans le nouveau, il faut donc procéder
ainsi:
class Tableau { double* tab; int n; public: Tableau(); Tableau(int a); Tableau(const Tableau& X){ n = X.n; tab = new double[n]; for (int i = 0; i<n; i++) tab[i] = X.tab[i]; } // autres champs et fonctions membres, // dont l'opérateur parenthèses précédemment introduit double& operator()(int a); };
Ainsi, si une fonction f
a été déclarée de la façon suivante:
void f(Tableau X);
alors dans le code suivant il y a un appel caché au constructeur par copie:
Tableau A(5); // appel au constructeur prenant // un int comme argument for (int i=0; i<A.n; i++) A(i) = i+1; Tableau B(A); // appel au constructeur par copie Tableau C = A; // appel au constructeur par copie aussi ! // équivalent à Tableau C(A); C = A; // appel à operator= (à ne pas confondre avec le = ci-dessus) f(A); // appel au constructeur par copie afin de recopier l'argument
car en effet cette dernière ligne se traduira par:
{ Tableau X = B; // appel au constructeur par copie ... // bloc écrit dans la définition de la fonction f }
Attention ! Le symbole =
dans une déclaration est un raccourci
pour appeler le constructeur par copie, alors que ce même symbole hors des
déclarations est l'opérateur =
!