Le quartierC++ C++Pièce 5/7Intermédiaire

Classes, constructeurs et RAII

Définir ses propres types avec les classes, initialiser un objet avec un constructeur et libérer ses ressources automatiquement grâce au destructeur (RAII).

Ce que tu vas apprendre

  • Écrire une classe avec des données privées et des méthodes publiques.
  • Initialiser un objet avec un constructeur.
  • Comprendre le destructeur et le principe RAII.

Une première classe

Une classe décrit un nouveau type qui regroupe des données et les fonctions qui les manipulent. Un objet est une instance de cette classe.

recette.cpp
#include <iostream>
#include <string>

class Recette {
public:
    std::string titre;
    int minutes;
};

int main() {
    Recette r{"Crêpes", 20};
    std::cout << r.titre << " : " << r.minutes << " min\n";
}

Le mot public rend les membres accessibles depuis l'extérieur. Les valeurs entre accolades initialisent les membres dans l'ordre de déclaration.

Encapsulation

Laisser les données publiques permet à n'importe qui de les mettre dans un état absurde (une durée négative, par exemple). L'encapsulation consiste à les rendre private et à passer par des méthodes :

class Recette {
public:
    int minutes() const { return minutes_; }
    void rallonger(int extra) { minutes_ += extra; }

private:
    std::string titre_;
    int minutes_{0};
};

Le const après minutes() promet que la méthode ne modifie pas l'objet. Le suffixe _ sur les membres privés est une convention répandue, pas une obligation.

struct est une classe dont les membres sont publics par défaut, alors que pour class ils sont privés. On réserve souvent struct aux simples regroupements de données.

Le constructeur

Un constructeur est une fonction spéciale appelée à la création de l'objet. Il porte le nom de la classe et n'a pas de type de retour :

class Recette {
public:
    Recette(std::string titre, int minutes)
        : titre_{std::move(titre)}, minutes_{minutes} {}

private:
    std::string titre_;
    int minutes_;
};

La partie après les deux-points est la liste d'initialisation : elle construit chaque membre directement avec la bonne valeur. std::move demande le déplacement de la chaîne au lieu de sa copie ; il faut #include <utility> pour l'utiliser.

Création d'un objet :

Recette r{"Tarte tatin", 60};

Le destructeur

Le destructeur s'exécute automatiquement quand l'objet disparaît, c'est-à-dire en fin de bloc pour une variable locale. Il se note ~NomDeLaClasse :

class Journal {
public:
    Journal()  { std::cout << "Ouverture\n"; }
    ~Journal() { std::cout << "Fermeture\n"; }
};

int main() {
    Journal j;
    std::cout << "Travail en cours\n";
}   // affiche « Fermeture » ici

La sortie est : Ouverture, Travail en cours, Fermeture. Le destructeur est appelé même si la fonction se termine par une erreur.

RAII

Le principe RAII (Resource Acquisition Is Initialization) tient en une phrase : une ressource est acquise dans le constructeur d'un objet et libérée dans son destructeur. Une ressource, c'est de la mémoire, un fichier ouvert, un verrou, une connexion.

#include <fstream>

void ecrire() {
    std::ofstream fichier{"recettes.txt"};
    fichier << "Crêpes\n";
}   // le fichier est fermé automatiquement

Tu n'as pas écrit de close(). L'objet fichier le fait dans son destructeur, quel que soit le chemin de sortie de la fonction.

C'est la raison pour laquelle on évite new et delete à la main. Une classe qui libère ses ressources toute seule supprime toute une catégorie de fuites.

La règle du zéro

Si ta classe ne contient que des membres qui se gèrent eux-mêmes (std::string, std::vector, pointeurs intelligents), tu n'écris ni destructeur, ni constructeur de copie : le compilateur génère les bons. C'est la règle du zéro, à viser par défaut.

Tu ne définis ces fonctions que si ta classe gère directement une ressource brute. Dans ce cas, applique aussi la règle des cinq : destructeur, constructeur de copie, affectation par copie, constructeur de déplacement et affectation par déplacement vont ensemble.

À retenir

  • Une classe regroupe des données et des méthodes ; on garde les données private.
  • Une méthode qui ne modifie pas l'objet se marque const.
  • Le constructeur initialise l'objet, de préférence via la liste d'initialisation.
  • Le destructeur ~Classe() s'exécute automatiquement à la destruction de l'objet.
  • RAII : acquérir la ressource dans le constructeur, la libérer dans le destructeur.
  • Vise la règle du zéro : laisse les membres standards gérer leurs ressources.

Pour aller plus loin

Sources officielles

Ensuite

Projet
Lignes de code
Niveau
Le quartier
Appartement
C++
Pièce
5/7
Plan n°
cpp/05.classes-et-raii
Lignes de code · fiches rédigées à partir des documentations officielles, sources citées en bas de chaque page.