Construction des objets

Chapitres traités   

Vu le principe d'encapsulation, il est formellement interdit d'atteindre directement les attributs d'une classe. Il faut systématiquement passer par une méthode. Cette technique est judicieuse puisque le changement d'état d'un objet passe d'abord par un changement de comportement. Du coup, il n'est pas possible de réaliser une initialisation explicite en utilisant les accolades comme nous avions l'habitude de procéder avec les structures. Ne vous inquiétez pas, il existe des méthodes adaptées pour résoudre les initialisations explicites pour que l'objet soit dans l'état désiré. Ces méthodes spécifiques s'appellent des constructeurs.


Choix du chapitre Constructeur

Un constructeur est une méthode qui sera appelée automatiquement à chaque création d'un objet. Ceci se fera quel que soit la classe d'allocation de l'objet : statique, automatique ( pile ) ou dynamique ( tas ). Le constructeur se reconnaît parce qu'il porte le même nom que la classe. Attention, un constructeur ne doit rien renvoyer. Cela n'aurait aucun sens puisque c'est la phase de création.


Choix du chapitre Création des objets

Un constructeur est une méthode, donc, lorsque nous créons un objet, nous devons faire appel explicitement à cette méthode, en utilisant la syntaxe habituelle de l'appel des fonctions, c'est-à-dire en utilisant les parenthèses. Pour le nombre complexe, nous avons besoin de préciser les deux arguments vu la signature du constructeur que nous avons choisi.

Nous savons que nous avons la possibilité d'initialiser explicitement une variable dynamique. Dans le cas d'une variable primaire ( int - par exemple), il s'agit dans la syntaxe de préciser le type de la variable et de donner entre parenthèse la valeur initiale. Dans le cas d'un objet, il est nécessaire de passer par la phase de création. Nous faisons donc appel explicitement au constructeur avec le nombre d'arguments requis.


Lorsque nous écrivons : «  int i = 5 ;  » le compilateur transforme cette ligne en  «  int i (5) ;  » parce qu'en C++ (contrairement au C) tous les types sont considérés comme des classes. Lors d'une initialisation explicite, c'est le constructeur préfabriqué qui comporte un seul paramètre qui est appelé.

Vous remarquez dans le code précédent que certaines lignes ne fonctionnent plus correctement. Deux lignes provoquent des erreurs de compilation. Avant d'évaluer la raison de ce problème, nous allons étudier la forme canonique d'une classe.

Choix du chapitre Forme canonique d'une classe

Le mécanisme des classes est très puissant. Au moment où nous créons une nouvelle classe, quatre méthodes sont automatiquement intégrées pour assurer un comportement minimum de la classe sans aucune écriture explicite. C'est ce qui s'appelle la « forme canonique d'une classe ». Ces quatre méthodes sont :

  1. Constructeur par défaut  : le constructeur par défaut est un constructeur qui ne possède pas de paramètre et donc qui n'attend pas d'argument. Par défaut, ce constructeur ne fait rien. Si vous désirez avoir un comportement particulier, il sera nécessaire de le redéfinir. Toutefois, ce constructeur n'existe plus à partir du moment au vous définissez un nouveau constructeur qui possède un nombre quelconque d'arguments. Si vous désirez, malgré tout, posséder, en plus, un constructeur par défaut, il sera également nécessaire de le redéfinir.
  2. Constructeur de copie  : il est possible de créer un objet à partir d'un autre objet (bien entendu, de la même classe). Ce constructeur attend l'objet en paramètre et copie chacun de ces attributs pour les associés à ses propres attributs. Le comportement par défaut est donc une copie membre à membre.
  3. Destructeur  : de même qu'il existe une phase de construction, il existe systématiquement une phase de destruction. Ce mécanisme est utile lorsque nous avons besoin de gérer des variables dynamiques pour notamment leurs libérations. Un destructeur se reconnaît parce qu'il porte le même nom que la classe précédé du tilde «  ~  ».
  4. Opérateur d'affectation  : nous avons déjà utilisé cet opérateur lorsque que nous avons réalisé des affectations  (des copies) de structures. Par défaut, comme pour le constructeur de copie, l'affectation propose une copie membre à membre. Ce comportement est très intéressant puisque nous n'avons pas besoin d'écrire quoi que se soit et c'est généralement ce que nous avons besoin. Il existe, malgré tout, des situations où ce comportement n'est pas souhaitable. Dans ce cas là, il sera nécessaire de redéfinir cet opérateur.

Toute l'étude que nous avons faite sur les fonctions s'applique pour les méthodes. A ce sujet, il est donc possible de faire de la surdéfinition et donc d'avoir, par exemple, plusieurs constructeurs. C'est justement ce qui se passe avec la forme canonique puisque deux constructeurs coexistent. Nous pouvons également utiliser des paramètres par défaut.

Choix du chapitre Retour sur la classe «  Complexe  » avec le principe de la forme canonique

Lorsque nous écrivons la classe «  Complexe  » comme ci-dessous à gauche, en réalité, nous avons ce qui est décrit sur la partie droite.

 

Choix du chapitre Définitions de plusieurs constructeurs

Grâce à la surdéfinition, il serait souhaitable de répondre à l'attente des utilisateurs, en proposant d'autres constructeurs, pour répondre à tous les cas de figure, c'est-à-dire :

  1. Pouvoir construire un nombre complexe sans préciser de valeurs initiales. Cela consiste à définir un constructeur par défaut. Ce nombre complexe doit représenter le point origine.
  2. Pouvoir construire, tout simplement un nombre réel, puisque les réels sont compris dans l'ensemble de définition des nombres complexes. Ce constructeur prendra un seul argument. La partie imaginaire doit être nulle.

 

Choix du chapitre Arguments par défaut

Au lieu d'avoir trois constructeurs différents, nous pouvons utiliser les arguments par défaut, et du coup, définir un seul constructeur qui traitera tous les cas de figure désirés.

Choix du chapitre Importance du constructeur par défaut

Quoi qu'il arrive, la création d'un objet doit toujours passer par une construction. C'est d'ailleurs pour cela qu'un constructeur par défaut existe, même si le programmeur n'en fabrique pas.

Revenons sur les tableaux d'objets. Deux cas peuvent se présenter. Soit nous devons déclarer un tableau d'objet sans initialisation explicite. A ce moment là, c'est le constructeur par défaut qui est sollicité pour construire chacun des objets en particulier. Si vous désirez effectuer une initialisation explicite, il suffit d'utiliser la syntaxe classique, c'est-à-dire, en utilisant les accolades, et de préciser pour chacun des objets, le constructeur adapté.

Souvenez-vous qu'il n'est pas possible d'initialiser explicitement chacune des cases d'un tableau dynamique. C'est bien sûr également vrai pour les tableaux d'objet, d'où l'importance d'avoir un constructeur par défaut.

Choix du chapitre Les objets constants

Nous pouvons avoir besoin de définir des objets constant comme cela a été le cas avec la variable complexe «  i  ». Le principe même d'un objet constant, c'est que ces attributs demeurent inchangés pendant toute sa durée de vie. Le principe de protection impose par défaut qu'un objet constant ne puisse utiliser aucune des méthodes, puisque l'une d'entre elle peut éventuellement proposer un changement d'état à l'objet, c'est-à-dire, modifier ses attributs.

Toutefois, il existe des méthodes qui ont un rôle uniquement consultatif, qui donc, par essence, ne change pas l'état de l'objet. Il serait intéressant que ces méthodes puissent être utilisées par ces objets constants. C'est notamment le cas pour la classe complexe qui utilisent deux méthodes consultatives ‘ module ' et ‘ argument '.

Lorsque vous décidez qu'un objet constant puisse utiliser certaines méthodes, ces dernières doivent être qualifiées de constantes. Les autres méthodes de la classe ne pourront donc pas être utilisées. Pour les objets qui ont le statut de variable (c'est-à-dire, non constant), ils pourront utiliser indifféremment les méthodes classiques et les méthodes constantes. Pour qu'une méthode devienne constante, il suffit de placer le suffixe «  const  » après sa signature.

Attention : Une méthode constante ne doit en aucun cas modifier un des attributs sinon le compilateur donnerait une erreur de compilation, ce qui va, bien entendu, dans le sens de nos propos.

Finalement, il peut être judicieux de définir toutes les méthodes consultatives comme des méthodes constantes, ce qui permettra par leurs signatures de les reconnaître.