Wer deine Daten anfassen darf
Als du deine erste Klasse geschrieben hast, hast du wahrscheinlich jeden Member der Außenwelt offengelegt. Das funktioniert, wirft aber einen der Hauptgründe weg, weshalb Klassen überhaupt existieren: Kapselung - den internen Zustand einer Klasse zu verbergen, sodass der Rest des Programms nur über eine kontrollierte Oberfläche mit ihr interagieren kann. Zugriffsspezifizierer sind die Art und Weise, wie du diese Grenze ziehst.
Es gibt genau drei: public, private und protected. Jeder kennzeichnet die Member, die ihm folgen, und die Kennzeichnung entscheidet, welcher Code sie lesen oder schreiben darf. Mach es richtig, und deine Klasse erzwingt ihre eigenen Regeln; mach es falsch, und irgendein Fehler irgendwo kann den Zustand deines Objekts beschädigen.
Die drei Spezifizierer
Ein Spezifizierer ist ein Schlüsselwort gefolgt von einem Doppelpunkt. Jeder danach deklarierte Member - bis zum nächsten Spezifizierer - fällt unter diese Zugriffsebene.
Kommentiere die letzte Zeile aus, und der Compiler weigert sich zu bauen: balance ist private, also kann main nicht direkt daran herumpfuschen. Genau das ist der Sinn - der einzige Weg, den Kontostand zu ändern, führt über deposit, was bedeutet, dass du später Validierung (keine negativen Einzahlungen, Protokollierung, Limits) an einer Stelle hinzufügen und darauf vertrauen kannst, dass sie immer angewendet wird.
Hier die vollständige Aufschlüsselung:
// erreichbar von...
// public überall (jeder Code, der das Objekt hat)
// private nur die eigenen Member der Klasse (+ friends)
// protected die eigenen Member der Klasse UND abgeleitete Klassen (+ friends)
class gegenüber struct: der Standard
Du kannst so viele Spezifizierer-Blöcke schreiben, wie du möchtest, in beliebiger Reihenfolge. Was Member vor dem ersten geschriebenen Spezifizierer bekommen, hängt davon ab, ob du class oder struct verwendet hast:
- In einer
classsind Member standardmäßigprivate. - In einem
structsind Member standardmäßigpublic.
Dieser Standard ist der einzige sprachliche Unterschied zwischen den beiden Schlüsselwörtern. Ein struct kann genau wie eine class Methoden, Konstruktoren und private-Abschnitte haben.
Konvention ist, struct für schlichte Bündel öffentlicher Daten zu verwenden und class, wenn du Verhalten und verborgenen Zustand willst - aber der Compiler erzwingt das nicht, nur der Standard unterscheidet sich.
Kapselung mit Gettern und Settern
Das alltägliche Muster lautet: Daten kommen in einen private-Abschnitt, und eine public-Methode gewährt kontrollierten Zugriff. Ein schreibgeschützter Getter gibt den Wert zurück; ein Setter validiert vor dem Zuweisen. Hier zahlt sich private aus.
Da celsius private ist, gibt es keine Möglichkeit, einen ungültigen Wert einzuschleusen - jeder Schreibzugriff muss durch setCelsius gehen, das die Invariante schützt. Beachte, dass die Getter mit const markiert sind: Sie versprechen, das Objekt nicht zu verändern, sodass du sie auch auf const Temperature-Objekten aufrufen kannst.
protected und Vererbung
protected spielt erst eine Rolle, sobald Vererbung ins Spiel kommt. Es verhält sich gegenüber externem Code wie private, aber eine abgeleitete Klasse kann darauf zugreifen. Verwende es für Member, die eine Unterklasse berechtigterweise braucht, die die Öffentlichkeit aber dennoch nicht haben sollte.
Ein häufiger Anfängerfehler ist, bei jedem Datenmember zu protected zu greifen, „nur für den Fall, dass eine Unterklasse es braucht". Das verbreitert stillschweigend den Vertrag deiner Klasse - jetzt kann jede Unterklasse von diesem Feld abhängen, und du kannst es nicht mehr frei ändern. Bevorzuge private und stufe nur dann auf protected hoch, wenn eine abgeleitete Klasse den Zugriff wirklich braucht.
Der friend-Notausgang
Manchmal braucht eine einzelne externe Funktion oder Klasse berechtigterweise Einblick in dein Innenleben - ein klassischer Fall ist ein Operator wie <<, den du nicht zum Member machen kannst. Das Schlüsselwort friend gewährt dieser einen benannten Entität Zugriff auf deine private- und protected-Member, und sonst nichts.
friend ist eine bewusste, chirurgische Ausnahme - die Klasse selbst benennt genau, wem sie vertraut, sodass sich niemand von außen Zugriff verschaffen kann. Verwende es sparsam; wenn du dich dabei ertappst, viele friends hinzuzufügen, hätten deine Member wahrscheinlich von vornherein nicht private sein sollen, oder dein Design muss überdacht werden.
Häufige Fehler, die du vermeiden solltest
- Jeden Member
publicmachen. Es fühlt sich einfach an, aber du verlierst die gesamte Validierung und die Invarianten, die dir die Kapselung verschafft. Standardmäßigprivate-Daten mitpublic-Methoden. - Den
class-Standard vergessen.class Foo { int x; };machtxprivate, also lässt sichfoo.x = 5nicht kompilieren. Wenn du ein schlichtes Datenbündel meintest, verwendestructoder füge einepublic:-Kennzeichnung hinzu. protectedüberstrapazieren. Es ist eine schwächere Grenze alsprivateund nur bei Vererbung relevant. Überall danach zu greifen, koppelt Unterklassen an Felder, die du vielleicht ändern willst.- Erwarten, dass
privateein Sicherheitsfeature ist. Es ist eine Compile-Zeit-Regel, die versehentlichen Zugriff verhindert, keine Verschlüsselung. Die Bytes liegen weiterhin im Speicher; beiprivategeht es um sauberes Design, nicht um Geheimhaltung.
Weiter: Structs
Du hast jetzt gesehen, dass ein struct eigentlich nur eine class ist, deren Member standardmäßig public sind. Die nächste Seite, Structs, geht darauf ein, wann dieser public-standardmäßig-Standard genau das ist, was du willst - leichtgewichtige Aggregate zum Gruppieren zusammengehöriger Werte - und wie struct im idiomatischen C++ neben vollwertigen Klassen verwendet wird.
Häufig gestellte Fragen
Was ist der Unterschied zwischen public, private und protected in C++?
public-Member sind von überall erreichbar. private-Member sind nur innerhalb derselben Klasse (und ihrer friends) erreichbar. protected verhält sich wie private, lässt aber zusätzlich abgeleitete Klassen auf den Member zugreifen. Per Konvention hält man Daten private und stellt das Verhalten über public-Methoden bereit.
Sind Member in C++ standardmäßig privat?
In einer class ja - alles ist private, bis du einen Zugriffsspezifizierer schreibst. In einem struct ist der Standard public. Dieser eine Standard ist der einzige echte Unterschied zwischen class und struct in C++; beide können Methoden, Konstruktoren und Zugriffsspezifizierer haben.
Was bewirkt das Schlüsselwort friend in C++?
friend gewährt einer bestimmten Funktion oder Klasse Zugriff auf deine private- und protected-Member. Es ist eine bewusste, eng begrenzte Ausnahme von der Kapselung - die Klasse benennt genau, wem sie vertraut, sodass Zugriff nie implizit gewährt wird.