Les constructeurs et les destructeurs en langage C++
La notion de constructeur
Le constructeur est la fonction membre appelée automatiquement lors de la création d'un
objet (en statique ou en dynamique). Cette fonction membre est la première fonction membre à être
exécutée, il s'agit donc d'une fonction permettant l'initialisation des variables.
Le constructeur d'un objet porte le même nom que la classe et ne possède aucune valeur
de retour (même pas void).
La définition de cette fonction membre spéciale n'est pas obligatoire (si vous ne souhaitez pas initialiser les données membres par exemple) dans la mesure où un constructeur par défaut (appelé parfois constructeur sans argument) est défini par le compilateur C++ si la classe n'en possède pas.
Voyons sur un exemple comment se déclare un constructeur :
class Toto{ private : int age; char sexe; float taille; public : Toto(int,char,float); }; Toto::Toto(int age, char sexe, float taille){ this->age = age; this->sexe = sexe; this->taille = taille; }
L'appel du constructeur se fait lors de la création de l'objet. De ce fait, l'appel du constructeur est différent selon que l'objet est créé de façon statique ou dynamique :
- en statique : le constructeur est appelé grâce à une instruction
constituée du nom de la classe, suivie par le nom que l'on donne à l'objet, et les
paramètres entre parenthèses.
Toto Toto1(12,'M',1.62);
- en dynamique : le constructeur est appelé en définissant un pointeur
vers un objet du type désiré puis en lui affectant la valeur retournée par
l'opérateur new.
Toto *pToto = new Toto(12,'M',1.62);
Comme pour n'importe quelle fonction membre, il est possible de surcharger les constructeurs, c'est-à-dire définir plusieurs constructeurs avec un nombre/type d'arguments différents. Ainsi, il sera possible d'initialiser différemment un même objet, selon la méthode de construction utilisée.
Imaginons par exemple que pour l'exemple précédent on veuille pouvoir définir le sexe de Toto grâce à un entier valant 0 ou 1, ainsi qu'avoir la possibilité de passer en paramètre la lettre 'M' ou 'F', on peut alors définir deux constructeurs pour lesquels le type du second argument sera différent. De plus, on va montrer de quelle manière il est possible de contrôler le caractère entré en paramètre :
class Toto{ private : int age; char sexe; float taille; public : Toto(int,char,float); Toto(int,int,float); }; Toto::Toto(int age, char sexe, float taille){ this->age = age; if ((sexe=='M')||(sexe=='F')) { this->sexe = sexe; } else printf("Erreur d'initialisation"); this->taille = taille; } Toto::Toto(int age, int sexe, float taille){ this->age = age; switch (sexe) { case 0 : this->sexe = 'F'; break; case 1: this->sexe = 'M'; break; default : printf("Erreur d'initialisation"); break; } this->taille = taille; }
Enfin, il est possible d'utiliser des valeurs par défaut pour les arguments, afin d'éviter à avoir à entrer de façon répétitive un ou plusieurs paramètres portant généralement la même valeur.
Les destructeurs
Les destructeurs sont en quelque sorte au constructeur ce que la mort est à la vie, c'est-à-dire qu'il s'agit d'une fonction membre qui intervient automatiquement lors de la destruction d'un objet. Il permet ainsi d'une certaine façon d'exaucer ses dernières volontés...
Le destructeur est une fonction membre dont la définition ressemble étrangement à celle du constructeur, hormis le fait que le nom du destructeur est précédé d'un tilde (~), et qu'il ne possède aucun argument.
Les destructeurs ont en général beaucoup moins besoin d'être définis que les constructeurs, c'est donc le destructeur par défaut qui est appelé le cas échéant. Toutefois, lorsque les objets sont chaînés dynamiquement grâce à des pointeurs (lorsqu'une fonction membre d'un objet est un pointeur vers un objet de même type par exemple), ou dans d'autres cas particuliers la définition d'un destructeur permettant de « nettoyer » l'ensemble des objets peut être indispensable !
Le destructeur, comme dans le cas du constructeur, est appelé différemment selon que l'objet auquel il appartient a été créé de façon statique ou dynamique.
- le destructeur d'un objet créé de façon statique est appelé de façon implicite dès que le programme quitte la portée dans lequel l'objet existe
- le destructeur d'un objet créé de façon dynamique doit être appelé grâce au mot clé delete, qui permet de libérer la mémoire occupée par l'objet.
Bien évidemment un destructeur ne peut être surchargé, ni avoir de valeur par défaut pour ses
arguments, puisqu'il n'en a tout simplement pas !