Classes, constructeurs et 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.
#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.
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
Références et pointeurs
Comprendre les adresses mémoire, passer des arguments sans copie avec les références et manipuler des pointeurs en sécurité.
Mémoire, pointeurs intelligents et bibliothèque standard
Distinguer pile et tas, gérer la propriété avec unique_ptr et shared_ptr, puis utiliser les algorithmes et std::map de la bibliothèque standard.
- Projet
- Lignes de code
- Niveau
- Le quartier
- Appartement
- C++
- Pièce
- 5/7
- Plan n°
- cpp/05.classes-et-raii