Menu

Spécificateurs d'accès en C++ : public, private, protected

Comment public, private et protected contrôlent qui peut toucher aux membres d'une classe en C++ - le fondement de l'encapsulation, avec les getters, les setters et l'échappatoire friend.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Qui a le droit de toucher à vos données

Quand vous avez écrit votre première classe, vous avez probablement exposé chaque membre au monde extérieur. Cela fonctionne, mais cela gâche l'une des principales raisons d'être des classes : l'encapsulation - cacher l'état interne d'une classe pour que le reste du programme ne puisse interagir avec elle qu'à travers une surface contrôlée. Les spécificateurs d'accès sont la façon dont vous tracez cette frontière.

Il y en a exactement trois : public, private et protected. Chacun étiquette les membres qui le suivent, et l'étiquette décide quel code est autorisé à les lire ou les écrire. Faites-le bien et votre classe applique ses propres règles ; faites-le mal et n'importe quel bug n'importe où peut corrompre l'état de votre objet.

Les trois spécificateurs

Un spécificateur est un mot-clé suivi de deux-points. Tout membre déclaré après lui - jusqu'au spécificateur suivant - relève de ce niveau d'accès.

Décommentez la dernière ligne et le compilateur refuse de construire : balance est private, donc main ne peut pas y toucher directement. C'est là tout l'intérêt - la seule façon de modifier le solde est via deposit, ce qui signifie que vous pourrez plus tard ajouter une validation (pas de dépôts négatifs, journalisation, limites) à un seul endroit et avoir l'assurance qu'elle est toujours appliquée.

Voici le détail complet :

//             accessible depuis...
// public      partout (tout code qui possède l'objet)
// private     uniquement les propres membres de la classe (+ friends)
// protected   les propres membres de la classe ET les classes dérivées (+ friends)

class par rapport à struct : la valeur par défaut

Vous pouvez écrire autant de blocs de spécificateurs que vous voulez, dans n'importe quel ordre. Ce que les membres obtiennent avant que vous n'écriviez le premier dépend de l'usage de class ou de struct :

  • Dans une class, les membres sont private par défaut.
  • Dans un struct, les membres sont public par défaut.

Cette valeur par défaut est la seule différence au niveau du langage entre les deux mots-clés. Un struct peut avoir des méthodes, des constructeurs et des sections private tout comme une class.

La convention est d'utiliser struct pour de simples regroupements de données publiques et class quand vous voulez du comportement et un état caché - mais le compilateur ne l'impose pas, seule la valeur par défaut diffère.

Encapsulation avec getters et setters

Le schéma quotidien est le suivant : les données vont dans une section private, et une méthode public donne un accès contrôlé. Un getter en lecture seule renvoie la valeur ; un setter valide avant d'affecter. C'est là que private porte ses fruits.

Comme celsius est private, il n'y a aucun moyen d'y glisser une valeur invalide - chaque écriture doit passer par setCelsius, qui protège l'invariant. Remarquez que les getters sont marqués const : ils promettent de ne pas modifier l'objet, vous pouvez donc aussi les appeler sur des objets const Temperature.

protected et l'héritage

protected ne compte qu'une fois que l'héritage entre en jeu. Il se comporte comme private pour le code extérieur, mais une classe dérivée peut y accéder. Utilisez-le pour des membres dont une sous-classe a légitimement besoin mais que le public ne devrait toujours pas atteindre.

Une erreur fréquente de débutant est de recourir à protected sur chaque membre de données « au cas où une sous-classe en aurait besoin ». Cela élargit silencieusement le contrat de votre classe - désormais chaque sous-classe peut dépendre de ce champ, et vous ne pouvez plus le modifier librement. Préférez private et ne passez à protected que lorsqu'une classe dérivée a réellement besoin de l'accès.

L'échappatoire friend

Parfois, une seule fonction ou classe extérieure a légitimement besoin de voir vos rouages internes - un cas classique est un opérateur comme << que vous ne pouvez pas faire membre. Le mot-clé friend accorde à cette unique entité nommée l'accès à vos membres private et protected, et à rien d'autre.

friend est une exception délibérée et chirurgicale - la classe elle-même nomme exactement à qui elle fait confiance, de sorte que personne ne peut s'accorder l'accès depuis l'extérieur. Utilisez-le avec parcimonie ; si vous vous retrouvez à ajouter beaucoup de friends, c'est probablement que vos membres n'auraient pas dû être private au départ, ou que votre conception doit être repensée.

Erreurs courantes à éviter

  • Rendre chaque membre public. Ça paraît simple, mais vous perdez toute la validation et les invariants que l'encapsulation vous offre. Par défaut, données private avec méthodes public.
  • Oublier la valeur par défaut de class. class Foo { int x; }; rend x private, donc foo.x = 5 ne compilera pas. Si vous vouliez un simple regroupement de données, utilisez struct ou ajoutez une étiquette public:.
  • Abuser de protected. C'est une frontière plus faible que private et elle n'est pertinente qu'avec l'héritage. Y recourir partout couple les sous-classes à des champs que vous pourriez vouloir modifier.
  • S'attendre à ce que private soit une fonctionnalité de sécurité. C'est une règle de compilation qui empêche l'accès accidentel, pas du chiffrement. Les octets sont toujours en mémoire ; private concerne une conception propre, pas le secret.

Suite : Structs

Vous avez désormais vu qu'un struct n'est en réalité qu'une class dont les membres sont public par défaut. La page suivante, structs, creuse les cas où cette valeur public-par-défaut est exactement ce que vous voulez - de légers agrégats pour regrouper des valeurs liées - et comment struct est utilisé dans le C++ idiomatique aux côtés de classes complètes.

Questions fréquentes

Quelle est la différence entre public, private et protected en C++ ?

Les membres public sont accessibles de partout. Les membres private ne sont accessibles que depuis l'intérieur de la même classe (et de ses friends). protected est comme private, mais permet en plus aux classes dérivées d'atteindre le membre. Par convention, on garde les données private et on expose le comportement via des méthodes public.

Les membres sont-ils privés par défaut en C++ ?

Dans une class, oui - tout est private jusqu'à ce que vous écriviez un spécificateur d'accès. Dans un struct, la valeur par défaut est public. Cette unique valeur par défaut est la seule véritable différence entre class et struct en C++ ; les deux peuvent avoir des méthodes, des constructeurs et des spécificateurs d'accès.

Que fait le mot-clé friend en C++ ?

friend accorde à une fonction ou une classe précise l'accès à vos membres private et protected. C'est une exception délibérée et étroite à l'encapsulation - la classe nomme exactement à qui elle fait confiance, de sorte que l'accès n'est jamais accordé implicitement.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER