Nous proposons ici l'étude d'une classe très simple, afin de montrer les différences fondamentales entre une classe en C++ et une structure en C. L'exemple de classe suivant nous permet de réintroduire les notions de construction et de destruction, ainsi que les opérations d'affectation et de copie.
Vous noterez que, par défaut, les membres d'une classe sont protégés, leur accès de l'extérieur de la classe est impossible, c'est le principe fondamental d'encapsulation: le maximum de détails sur l'implémentation d'une classe doit être masqué, cela permet une certaine indépendance qui facilite la maintenance de la classe. L'accès (et le contrôle) aux attributs est généralement permis en lecture et/ou en écriture par des méthodes qu'on nomme des accesseurs (cf. chapitre suivant).
Pour créer un objet de la classe
La seconde possibilité est d'allouer dynamiquement un objet.
Dans les deux cas, le constructeur dit par défaut est appelé. Le rôle de cette méthode est de préciser comment construire un objet standard (i.e. avec des valeurs par défaut) de la classe, sans que l'utilisateur ne précise aucun paramètre. Dans notre exemple, comme nous n'avons pas écrit de constructeur, un constructeur par défaut est alors automatiquement fourni, équivalent à ce qui suit.
Rappelons que créer (dit également instancier) un objet se déroule
en deux phases. La première consiste en l'allocation de l'espace mémoire
nécessaire à l'élément, ce qui est effectué sur la pile et
automatiquement dans le cas (1), ou dynamiquement dans la mémoire centrale dans le
cas (2). Une fois l'allocation réalisée, un constructeur est appelé, et
dans notre cas il s'agit du constructeur par défaut. Cependant, avant d'exécuter le
constructeur même, la construction des attributs de l'objet doit être
réalisée. C'est le propos du symbole
Remarquons que si l'on change l'ordre de construction des attributs, le compilateur émet alors un avertissement et les replace dans l'ordre de déclaration. En résumé, les attributs sont toujours construits selon leur ordre de déclaration. Il faut également noter que dans le cas où les attributs sont d'un type primitif (entier, flottant, booléen...), ils ne sont pas initialisés si l'on ne précise pas de valeur au constructeur. Il est possible de proposer autant de constructeurs qu'on souhaite (à condition qu'ils aient une signature - i.e. la liste des types de leurs arguments - différente). Cela permet de fournir tous les paramètres désirés à la construction d'un objet.
Ainsi, nous pouvons créer un objet de la manière suivante.
Il est à noter que, dès qu'on définit un constructeur, le constructeur par défaut n'est plus fourni automatiquement par le compilateur, et qu'il faut donc le réécrire si nécessaire.
Le compilateur fournit également automatiquement un constructeur dit de copie, qui est disponible même si on définit d'autres constructeurs (contrairement au constructeur par défaut). Son rôle est d'initialiser un nouvel objet de la classe en copiant une instance existante. Dans notre exemple, le constructeur de copie fourni par défaut est équivalent à ce qui suit.
Cela signifie que, par défaut, le constructeur de copie appelle le constructeur de copie de chaque attribut pour recopier l'objet. Voici un exemple d'utilisation du constructeur de copie.
La seconde ligne appelle le constructeur de copie de la classe. Les attributs de l'instance
A partir de l'exemple précédent, considérons l'instruction suivante,
en dehors de toute déclaration:
Cet opérateur appelle automatiquement l'opérateur d'affectation de chacun des attributs afin de recopier totalement l'objet en paramètre. Dans notre exemple, l'affectation est équivalente à l'appel suivant.
Au cours d'un programme, les objets créés sont naturellement amenés à être supprimés. Cette procédure se déroule en deux étapes (à l'image de la création d'un objet). Tout d'abord, l'appel au destructeur de l'objet et ensuite la libération de la mémoire occupée par l'objet. Dans le cas de la création d'une variable (cf. le cas (1) dans la section sur la construction), la suppression s'effectue à la fin du bloc où a été déclarée la variable. Dans le cas d'une allocation dynamique (cf. le cas (2) dans la section sur la construction), l'utilisateur doit décider du moment de la destruction par la commande suivante.
Il faut noter, à l'image de la création d'un objet, qu'entre l'appel au destructeur et la libération de la mémoire, les attributs sont détruits dans l'ordre inverse de leur déclaration. A l'opposé de la construction, l'utilisateur ne peut pas intervenir dans ce processus. Un destructeur est toujours fourni par défaut, mais il n'effectue aucune opération particulière.
|