Ce qu'est une classe
Une classe est un plan pour un type personnalisé qui regroupe données (variables membres) et comportement (fonctions membres) en une seule unité. Là où les types intégrés comme int et double décrivent des valeurs uniques, une classe vous permet de modéliser un concept entier - un compte bancaire, un point 2D, un joueur - sous la forme d'une seule valeur que vous pouvez faire circuler.
Vous avez déjà utilisé des classes sans en définir aucune : std::string et std::vector sont des classes de la bibliothèque standard. Appeler name.length() ou v.push_back(3), c'est appeler une fonction membre sur un objet. Vous allez maintenant construire vos propres types de la même manière, puis passer aux constructeurs pour les initialiser.
Définir une classe et créer des objets
La définition d'une classe énumère ses membres entre accolades et se termine par un point-virgule - oublier ce ; final est l'une des erreurs les plus courantes des débutants. Chaque objet que vous créez à partir de la classe possède sa propre copie des variables membres.
rex et luna sont deux objets distincts. Modifier rex.name ne touche pas à luna.name - chaque objet détient ses propres données. Vous accédez à un membre avec l'opérateur point . sur un objet (ou -> lorsque vous disposez d'un pointeur vers un objet).
public vs private
Par défaut, tout dans une class est private : seules les fonctions membres de la classe elle-même peuvent y toucher. L'étiquette public: ouvre les membres au code extérieur. Cette séparation est le cœur de l'encapsulation - vous exposez une interface sûre et cachez les données internes pour qu'elles ne puissent pas être mises dans un état invalide.
Comme count est private, aucun appelant ne peut y glisser une valeur négative ou absurde - il doit passer par increment(). Le const après la liste de paramètres de value() garantit que la fonction ne modifiera pas l'objet, ce qui permet de l'appeler sur des objets const et signale l'intention aux lecteurs. Consultez les spécificateurs d'accès pour tout savoir sur public, private et protected.
Déclaration vs définition des méthodes
Pour les petites classes, définir les méthodes en ligne (comme ci-dessus) convient parfaitement. Pour les plus grandes, il est courant de déclarer les méthodes dans la classe et de définir leur corps à l'extérieur, à l'aide de la syntaxe de portée ClassName::method. Cela garde la définition de la classe lisible, telle un résumé de l'interface.
Le préfixe Rectangle:: indique au compilateur à quelle classe appartient la fonction. À l'intérieur d'une telle définition, vous désignez toujours les membres par leur nom simple (width, area()) - le compilateur sait qu'ils appartiennent à l'objet sur lequel la méthode a été appelée.
Le pointeur this
À l'intérieur de toute fonction membre non statique, this est un pointeur vers l'objet sur lequel la fonction a été invoquée. Vous n'en avez généralement pas besoin, puisqu'un simple nom de membre désigne déjà l'objet courant. Il devient utile lorsqu'un paramètre masque (shadow) un membre - ils portent le même nom - et que vous devez lever l'ambiguïté.
Sans this->, écrire x = x; dans setX affecterait le paramètre à lui-même et laisserait le membre inchangé - un bug silencieux. this->x lève toute ambiguïté. Beaucoup de bases de code évitent complètement le problème en nommant les paramètres différemment (par ex. setX(int newX)), mais vous verrez this-> en permanence dans du code réel.
Erreurs courantes
Une poignée de pièges liés aux classes attrapent les gens à répétition :
- Oublier le point-virgule de fin. La définition d'une classe se termine par
};. Retirez le;et vous obtenez un flot d'erreurs déroutantes pointant vers ce qui vient après la classe, pas vers la classe elle-même. - Oublier d'initialiser les membres. Les membres de types intégrés comme
intetdoublene sont pas mis à zéro automatiquement. Lire un membre non initialisé est un comportement indéfini. Donnez aux membres des valeurs par défaut (int count = 0;) ou initialisez-les dans un constructeur. - Accéder aux membres private depuis l'extérieur.
c.count = 5;sur un membre private est une erreur de compilation - passez plutôt par une méthode publique. C'est l'encapsulation qui fonctionne comme prévu. - Confondre la classe avec un objet.
Dog.bark();est faux -Dogest le type. Vous appelez des méthodes sur des objets :rex.bark();.
// Membre non initialisé - lire 'age' est un comportement indéfini :
class Cat {
public:
int age; // pas de valeur par défaut
};
Cat c;
std::cout << c.age; // valeur aléatoire, pas 0
Suite : Les constructeurs
Affecter chaque membre à la main après avoir créé un objet - rex.name = ...; rex.age = ...; - est fastidieux et facile à oublier, et c'est exactement ainsi qu'on se retrouve avec des membres non initialisés. La page suivante couvre les constructeurs : des fonctions spéciales qui s'exécutent automatiquement à la création d'un objet, vous permettant de garantir que chaque objet démarre dans un état valide grâce à une syntaxe nette en une ligne Dog rex("Rex", 4);.
Questions fréquentes
Quelle est la différence entre une classe et un objet en C++ ?
Une classe est le plan - elle décrit quelles données (variables membres) et quel comportement (fonctions membres) possède un type. Un objet est une instance concrète construite à partir de ce plan. class Dog { ... }; définit le type une seule fois ; Dog rex; crée un véritable Dog que vous pouvez utiliser. Une même classe peut produire de nombreux objets indépendants.
Quelle est la différence entre class et struct en C++ ?
Techniquement, seulement le niveau d'accès par défaut : les membres d'une class sont private par défaut, tandis que ceux d'une struct sont public par défaut. Les deux peuvent avoir des fonctions membres, des constructeurs et de l'héritage. Par convention, struct sert aux simples regroupements de données et class aux types dotés de comportement et d'invariants à protéger.
À quoi sert le pointeur this dans une classe C++ ?
À l'intérieur d'une fonction membre, this est un pointeur vers l'objet sur lequel la fonction a été appelée. Utilisez-le pour distinguer un paramètre d'un membre (this->x = x;) ou pour renvoyer l'objet courant. Vous en avez rarement besoin pour un accès membre normal - écrire x désigne déjà le x de l'objet courant.