Constructeurs et destructeur d'une classe en C++

25 Sep 2019 25 Sep 2019 28120 vues ESSADDOUKI Mostafa 6 min de lecture
Introduction et syntaxe de base
1 Introduction au langage C++ 2 Entrée-sortie en C++ - cin et cout 3 Inférence de type avec le mot-clé auto en C++ 4 Classe std::string et les chaînes de caractères en C++ 5 Les structures conditionnelles (if et switch) en C++ (C++17 et C++20) 6 Les boucles en C++ (C++17 et C++20) 7 La gestion des fichiers en C++
Pointeurs et fonctions
8 Introduction aux pointeurs en C++ - Déclaration et interêts 9 Les références en C++ - déclaration et interêts 10 Les tableaux en C++ - Déclaration et interêts 11 Introduction aux fonctions en C++ 12 Passer des arguments à une fonction en C++ 13 Déclarer un paramètre const en C++ 14 Les fonctions Lambda en C++ 15 Fonctions utiles (Mathématiques et caractères) en C++
Programmation OO
16 Classes et objets en C++ 17 Spécificateurs d'accès en C++ 18 Constructeurs et destructeur d'une classe en C++ 19 Fonctions membres en C++ 20 Membres statiques d'une classe en C++ 21 Fonctions en ligne en C++ - inline 22 Fonctions et classes amies en C++ - friend 23 Surcharge des fonctions en C++ 24 Surcharge des opérateurs en C++ 25 Héritage en C++ 26 La gestion d'exceptions en C++ : déclaration, utilisation et personnalisation 27 fonctions et classes templates en C++ 28 Les nouveautés C++20 pour améliorer les templates en C++
Structures de données
29 Introduction aux structures de données 30 Les structures en C++ et la différence avec les structures en C 31 Les listes chaînées en C++ 32 Les piles en C++ 33 File d'attente en C++ 34 Arbre binaire de recherche : définition et mise en oeuvre en C++
La bibliothèque standard (STL)
35 Introduction à la bibliothèque de Template Standard STL 36 Les itérateurs en C++ - définition, déclaration et exemples 37 La classe array en C++ (bibliothèque STL) <array> 38 La classe vector de la bibliothèque STL <vector> 39 La classe deque en C++ ( Bibliothèque STL) 40 La classe list en C++ (bibliothèque STL) <list> 41 La classe stack (Pile) en C++ (bibliothèque STL) <stack> 42 La classe queue (File d'attente) en C++ (bibliothèque STL) <queue> 43 La file d'attente prioritaire (classe priority_queue) - Bibliothèque STL 44 Les ensembles en C++ (Classe set <set> - Bibliothèque STL) 45 Les dictionnaires en C++ : Classe map (Bibliothèque STL) 46 Introduction aux algorithmes de la bibliothèque STL (programmation compétitive) 47 Tri et méthodes associées en C++ - Bibliothèque STL 48 Recherche dichotomique et méthodes associées en C++ - Bibliothèque STL 49 Appliquer un prédicat ou une fonction aux éléments d'une séquence en C++ - Bibliothèque STL 50 Recherche dans une séquence et méthodes associées en C++ - Bibliothèque STL

En C++, un constructeur est une fonction membre spéciale qui est automatiquement appelée lors de la création d'un objet. Un destructeur est appelé automatiquement lors de sa destruction. Ces deux mécanismes garantissent l'initialisation et le nettoyage corrects des ressources.

Constructeur Un constructeur porte exactement le même nom que la classe, n'a aucun type de retour (même pas void), et est appelé automatiquement à chaque instanciation d'un objet.

C++ propose trois types de constructeurs :

  • Constructeur par défaut — sans paramètres
  • Constructeur d'initialisation (paramétré) — avec paramètres
  • Constructeur par copie — initialise un objet depuis un autre objet de même type

Constructeur par défaut

Un constructeur par défaut ne prend aucun paramètre. Il sert généralement à donner des valeurs initiales aux membres. Si aucun constructeur n'est défini, le compilateur en génère un automatiquement (corps vide).

  Exemple

#include <iostream>
using namespace std;

class Voiture {
private:
    int    Id;
    double vitesse;

public:
    Voiture() // constructeur par défaut
    {
        Id = 1;
        vitesse = 250.5;
        cout << "Constructeur par défaut appelé." << endl;
    }
};

int main()
{
    Voiture v1; // déclenche automatiquement le constructeur
    return 0;
}
Sortie
Constructeur par défaut appelé.

Constructeur d'initialisation (paramétré)

On peut passer des arguments au constructeur pour initialiser l'objet avec des valeurs spécifiques dès sa création.

  Exemple 1 — corps du constructeur

Voiture(int a, double b)
{
    Id = a;
    vitesse = b;
    cout << "Constructeur paramétré appelé." << endl;
}

// Appel implicite
Voiture v1(1, 250.5);

// Appel explicite (équivalent)
Voiture v2 = Voiture(2, 140.0);

Liste d'initialisation

C++ offre une syntaxe plus concise et plus efficace : la liste d'initialisation, placée après le : dans l'en-tête du constructeur. Elle est obligatoire pour les membres const ou de type référence.

   
Syntaxe — liste d'initialisation C++
NomClasse(type a, type b) : membre1(a), membre2(b)
{
    // corps optionnel
}

  Exemple 2 — avec liste d'initialisation

#include <iostream>
using namespace std;

class Voiture {
private:
    int    Id;
    double vitesse;

public:
    Voiture(int a, double b) : Id(a), vitesse(b)
    {
        cout << "Constructeur paramétré — Id=" << Id
             << ", vitesse=" << vitesse << endl;
    }
};

int main()
{
    Voiture v1(1, 250.5);
    Voiture v2(2, 140.0);
    return 0;
}
Sortie
Constructeur paramétré — Id=1, vitesse=250.5
Constructeur paramétré — Id=2, vitesse=140
Surcharge de constructeurs On peut définir plusieurs constructeurs dans une même classe (surcharge), à condition que leurs signatures (nombre ou types de paramètres) soient différentes.

Constructeur par copie

Constructeur par copie Initialise un nouvel objet en copiant les données d'un objet existant de même type. Sa signature est : NomClasse(const NomClasse &autreObjet);

Il est automatiquement invoqué lors de :

  • l'initialisation d'un objet depuis un autre : Voiture v2 = v1;
  • le passage d'un objet par valeur à une fonction
  • le retour d'un objet par valeur depuis une fonction

  Exemple

#include <iostream>
using namespace std;

class Voiture {
private:
    int    Id;
    double vitesse;

public:
    Voiture(int a, double b) : Id(a), vitesse(b) {}

    // constructeur par copie
    Voiture(const Voiture &v) : Id(v.Id), vitesse(v.vitesse)
    {
        cout << "Constructeur par copie appelé." << endl;
    }

    void afficher() {
        cout << "Id=" << Id << " - Vitesse=" << vitesse << endl;
    }
};

int main()
{
    Voiture v1(1, 250.5);
    Voiture v2 = v1;  // déclenche le constructeur par copie
    v2.afficher();
    return 0;
}
Sortie
Constructeur par copie appelé.
Id=1 - Vitesse=250.5
Copie profonde (deep copy) Si la classe contient des pointeurs vers de la mémoire allouée dynamiquement, il est indispensable d'écrire un constructeur par copie personnalisé pour copier les données (et non juste l'adresse). Sinon, les deux objets partageront la même zone mémoire — source de bugs.

Destructeur

Destructeur Le destructeur est appelé automatiquement quand un objet sort de sa portée ou quand on lui applique delete. Il porte le nom de la classe précédé du symbole ~, n'a ni paramètre ni type de retour. Il sert à libérer les ressources allouées (mémoire dynamique, fichiers ouverts…).

  Exemple — libération de mémoire dynamique

#include <iostream>
#include <cstring>
using namespace std;

class Voiture {
private:
    char  *marque;
    int    Id;
    double vitesse;

public:
    Voiture(const char *m, int a, double b)
    {
        marque = new char[strlen(m) + 1];
        strcpy(marque, m);
        Id = a; vitesse = b;
    }

    ~Voiture() // destructeur
    {
        cout << "Destructeur appelé — libération de " << marque << endl;
        delete[] marque;
    }

    void afficher() {
        cout << "Id=" << Id << " Vitesse=" << vitesse
             << " Marque=" << marque << endl;
    }
};

int main()
{
    Voiture v1("BMW", 1, 250.5);
    v1.afficher();
    return 0; // le destructeur est appelé ici automatiquement
}
Sortie
Id=1 Vitesse=250.5 Marque=BMW
Destructeur appelé — libération de BMW
Fuite mémoire Si la classe alloue de la mémoire dynamique (avec new) sans définir de destructeur, cette mémoire ne sera jamais libérée : c'est une fuite mémoire. Toujours écrire un destructeur quand on utilise new.
Règle des 3 (Rule of Three) Si vous devez écrire l'un des trois éléments suivants, vous devez probablement écrire les trois : destructeur, constructeur par copie, opérateur d'affectation. Cette règle s'applique dès qu'un pointeur est membre de la classe.

Discussion (0)

Soyez le premier à laisser un commentaire !

Laisser un commentaire

Votre commentaire sera visible après modération.