EPFL
Faculté Informatique & Communications
Cours d'informatique

Mini-Référence :
Introduction à la POO : Constructeur et Destructeur
Surcharge d'opérateurs


L'opérateur ::

Lorsque les définitions des classes deviennent complexes, il est intéressant de pouvoir simplifier l'écriture des déclarations. C'est (en partie) le rôle de l'opérateur de résolution de portée :: qui permet ainsi d'écrire les définitions des méthodes d'une classe à l'extérieur de la déclaration de la classe.
À l'aide de :: le programmeur peut se contenter d'indiquer les prototypes des méthodes dans la déclaration de la classe et donner les définitions correspondantes, à l'extérieur de la déclaration, sous la forme de définition de fonctions de nom :

nom_classe::nom_fonction

Constructeurs et destructeurs

Les constructeurs et destructeurs sont des méthodes particulières, qui sont invoquées respectivement à la création et à la destruction d'un objet. Toute classe a (au moins) un constructeur et un destructeur, par défaut fourni par le compilateur (dans ce cas, ces constructeurs et destructeurs sont extrêmement basiques, et se contentent d'initialiser ou détruire les attributs pour lesquels ces opérations ont un sens). En conséquence, il est souvent nécessaire de les redéfinir, afin de gérer certaines actions particulières devant avoir lieu lors de la création ou de la destruction d'un objet; de fait, c'est presque une obligation dans le cas des constructeurs, et souvent nécessaire pour le destructeur et les constructeurs spécifiques (typiquement lorsque l'objet doit mobiliser une ressource non duplicable, tel que la mémoire, un périphérique, un fichier, etc.)

Déclaration

Pour que le compilateur puisse identifier les constructeurs et destructeurs, ces derniers doivent être prototypés différemment que les autres méthodes :

Constructeur(s)
  • Aucune indication de type de retour (pas même void)
  • Identificateur identique à celui de la classe
Destructeur
  • Aucune indication de type de retour (pas même void)
  • Identificateur identique à celui de la classe, précédé du signe «~» (tilde)
  • Liste d'argument vide

Constructeur de copie

Il existe un constructeur, appelé constructeur de copie, qui joue un rôle particulier: c'est le constructeur utilisé lorsque l'on cherche à obtenir une nouvelle instance, copie d'une autre instance déjà initialisée. Ce constructeur est important, car c'est celui qu'utilise le compilateur lorsqu'il doit effectuer de telles copies (par exemple lors du passage par valeur d'une instance à une fonction ou une méthode)

Le prototype du constructeur de copie est figé: le constructeur doit admettre un et un seul argument, qui est l'instance à dupliquer, passée par référence.
Si ce constructeur n'est pas explicitement défini par le programmeur, le compilateur se chargera d'en fabriquer un, réalisant une copie membre à membre des attributs.

Invocation des constructeurs et destructeurs

L'invocation des constructeurs est semi-explicite, en ce sens que, dans la plupart des cas, le programmeur choisi le moment et quel constructeur il faut invoquer, mais l'invocation des destructeurs est [presque] toujours implicite. En d'autre terme, le programmeur connaît le contexte dans lequel un objet est créé, mais ne peut pas connaître le contexte dans lequel l'objet est détruit.

 

Exemple

class Rectangle
{
  public:

    int hauteur, largeur;        // deux attributs publics

    Rectangle();                 // le constructeur par défaut
    Rectangle(int);              // un constructeur
    Rectangle(int,int);          // un autre constructeur
    Rectangle(const Rectangle&); // le constructeur de copie

    ~Rectangle();                // le destructeur

    // ... des méthodes ...

};

/* Définition des méthodes */

Rectangle::Rectangle() // cstr par défaut
: hauteur(0),   // section d'initialisation des attributs
  largeur(0)
{ }

Rectangle::Rectangle(int d) // cstr quelconque
: hauteur(d),
  largeur(d)
{ }

Rectangle::Rectangle(int h, int l) // cstr quelconque
: hauteur(h),
  largeur(l)
{ }

Rectangle::Rectangle(const Rectangle& r) // cstr de copie
: hauteur(r.hauteur),
  largeur(r.largeur)
{ }


int main()
{
  Rectangle r1;       // inst. & invoc. du constructeur par défaut
  Rectangle r2(18);   // inst. & invoc. d'un constructeur

  { // un bloc
    Rectangle r3(r1); // inst. & invoc. du constructeur de copie

    ...

  }   // -> invocation implicite du destructeur de r3 car
      //    sa portée est maintenant dépassée

  ...

}     // -> invocation implicite des destructeurs de r1 et r2


La surcharge des opérateurs

Il est possible de définir des opérateurs agissant sur les instances d'une classe, et d'utiliser ces opérateurs comme les opérateurs mathématiques et logiques du C++ (opérateurs +, -, *, /, <, >, ==, ...).

Pour cela, on définit, au niveau de la classe, une méthode nommée: "operator+", "operator-", "operator*", ...

La méthode ainsi créée peut alors s'appeler par "A + B", ou indifféremment par "A.operator+(B)".

Exemple :

Pour utiliser l'opérateur * sur des objets de classe MaClasse, on définit dans MaClasse la méthode suivante :
    MaClasse operator* (MaClasse x)
    {
        MaClasse valeur_de_retour;
        // corps de la méthode
        ...
        return valeur_de_retour;
    }

L'opérateur peut alors être utilisé avec :

   MaClasse A,B,C;
   // affectation de valeurs à A et B
   ...
   C = A * B;

Dernière mise à jour : $Date: 2009-09-11 17:10:52 +0200 (Fri, 11 Sep 2009) $  ($Revision: 25 $)