Kapselung und Zugriffsmodifizierer in C++ (public, protected, private)
Lernen Sie Kapselung und Zugriffsmodifizierer in C++, um sichere und gut strukturierte Klassen zu entwickeln.
Encapsulation (Kapselung) ist eines der vier grundlegenden Konzepte der objektorientierten Programmierung (OOP). Es bedeutet, dass die Daten (Eigenschaften) einer Klasse vor der Außenwelt verborgen werden und nur über definierte Methoden zugänglich sind. Dieser Ansatz bewahrt die Datenintegrität und macht die interne Struktur einer Klasse unabhängig von der externen Nutzung.
1) Was ist Encapsulation?
Encapsulation ist das Prinzip der „Datenverbergung“. Die internen Details einer Klasse (Eigenschaften, Hilfsmethoden) sind von außen nicht sichtbar. Der Benutzer interagiert nur über die öffentliche Schnittstelle der Klasse.
Vorteile der Kapselung:
- Daten werden vor falscher oder unerlaubter Nutzung geschützt.
- Die interne Logik der Klasse kann geändert werden, ohne dass externer Code beeinflusst wird.
- Erhöhte Sicherheit, Wartbarkeit und Testbarkeit.
2) Zugriffsmodifizierer
In C++ gibt es drei Zugriffsmodifizierer:
| Modifizierer | Zugriffsebene | Verwendung |
|---|---|---|
public |
Überall zugänglich | Öffentliche Schnittstelle (API) der Klasse |
protected |
Nur innerhalb der Klasse und abgeleiteten Klassen zugänglich | Gemeinsame Funktionalität für Vererbung |
private |
Nur innerhalb der Klasse zugänglich | Datenfelder, Hilfsfunktionen |
3) Beispiel zur Kapselung mit der Klasse Book
Im Folgenden ein Beispiel für eine Book-Klasse, die das Prinzip der Kapselung demonstriert.
#include <iostream>
#include <string>
using namespace std;
class Book {
private:
string title;
string author;
double price;
int pageCount;
public:
// Konstruktor
Book(string t, string a, double p, int pc)
: title(t), author(a), price(p), pageCount(pc) {}
// Getter und Setter
string GetTitle() const { return title; }
string GetAuthor() const { return author; }
double GetPrice() const { return price; }
void SetPrice(double p) {
if (p >= 0) price = p;
else cout << "Der Preis darf nicht negativ sein!" << endl;
}
int GetPageCount() const { return pageCount; }
void Print() const {
cout << "Buch: " << title
<< " | Autor: " << author
<< " | Seiten: " << pageCount
<< " | Preis: " << price << " €" << endl;
}
};
int main() {
Book b("C++ Primer", "Lippman", 180.0, 950);
b.Print();
b.SetPrice(-50); // Ungültig
b.SetPrice(210);
b.Print();
}
Private Felder können nicht direkt verändert werden.
Änderungen dürfen nur über kontrollierte Methoden wie SetPrice() erfolgen.
4) Geschützte (protected) Felder und Vererbung
Abgeleitete Klassen können direkt auf protected-Felder zugreifen.
Dies ermöglicht es der Unterklasse, die Daten der Basisklasse zu erweitern oder wiederzuverwenden.
class EBook : public Book {
protected:
string format; // z. B.: PDF, EPUB
public:
EBook(string t, string a, double p, int pc, string f)
: Book(t, a, p, pc), format(f) {}
void PrintWithFormat() const {
cout << GetTitle() << " (" << format << ")" << endl;
}
};
Die abgeleitete Klasse fügt hier ein neues Merkmal (format) hinzu, ohne die Kapselung zu verletzen.
5) Das friend-Schlüsselwort
Normalerweise können auf private-Mitglieder nur innerhalb der Klasse zugegriffen werden.
Es kann jedoch vorkommen, dass eine andere Klasse oder Funktion auf diese privaten Daten zugreifen muss.
In diesem Fall kann eine friend-Deklaration verwendet werden.
class Book {
private:
string title;
double price;
public:
Book(string t, double p) : title(t), price(p) {}
// friend-Funktionsdeklaration
friend void ApplyDiscount(Book& b, double rate);
};
void ApplyDiscount(Book& b, double rate) {
b.price *= (1 - rate); // Zugriff auf private Variable
}
int main() {
Book b("Design Patterns", 300);
ApplyDiscount(b, 0.1);
}
Die Verwendung von friend sollte mit Vorsicht erfolgen, da sie die Kapselung verletzt.
Sie sollte nur in Ausnahmefällen verwendet werden (z. B. bei Operatorüberladung oder Debugging-Werkzeugen).
6) Gestaltungsprinzipien für Getter und Setter
- Verwenden Sie Inline-Getter (
const) für einfache Datenzugriffe. - Führen Sie in Settern immer eine Validierung durch.
- Machen Sie Felder readonly (nur Getter), wenn Änderungen nicht erlaubt sind.
- Statt unnötiger Getter/Setter sollten Sie das Verhalten direkt über Methoden abstrahieren.
class Book {
private:
string title;
double price;
public:
Book(string t, double p) : title(t), price(p) {}
string GetTitle() const { return title; } // Nur lesen
void ApplyDiscount(double rate) { price *= (1 - rate); } // Verhalten statt Setter
};
7) Datensicherheit mit dem const-Schlüsselwort
const-Methoden verändern den Zustand der Klasse nicht.
Dies unterstützt die Kapselung und verhindert unbeabsichtigte Änderungen.
class SafeBook {
private:
string title;
public:
SafeBook(string t) : title(t) {}
string GetTitle() const { return title; } // const-Methode
void SetTitle(string t) { title = t; }
};
Wenn eine Get-Methode ohne const deklariert wird, verletzt sie dieses Prinzip und kann zu unerwarteten Fehlern führen.
8) Unveränderliches (Immutable) Objektmuster
Gemäß dem Kapselungsprinzip können einige Objekte als „unveränderlich“ (immutable) entworfen werden.
Alle ihre Mitglieder sind const und es gibt keine Setter-Methoden.
class ImmutableBook {
private:
const string title;
const string author;
const int pages;
public:
ImmutableBook(string t, string a, int p)
: title(t), author(a), pages(p) {}
string GetTitle() const { return title; }
string GetAuthor() const { return author; }
int GetPages() const { return pages; }
};
Dieser Ansatz gewährleistet Datenintegrität, insbesondere in Multi-Threading-Umgebungen.
9) Kapselung und Zustandsverwaltung von Objekten
Kapselung steuert nicht nur den Zugriff, sondern stellt auch sicher, dass ein Objekt in einem gültigen Zustand bleibt. Der interne Zustand der Klasse sollte stets gültige Werte haben.
class ValidatedBook {
private:
double price;
public:
void SetPrice(double p) {
if (p < 0) throw invalid_argument("Der Preis darf nicht negativ sein.");
price = p;
}
};
Solche Validierungsmechanismen garantieren, dass die Klasse einen „gültigen Zustand“ beibehält und verhindern ungültige Eingaben von außen.
10) TL;DR
- Kapselung bedeutet, Daten zu verbergen und über Verhalten kontrolliert darauf zuzugreifen.
private: nur innerhalb der Klasse zugänglich.protected: innerhalb der Klasse und abgeleiteten Klassen zugänglich.public: überall zugänglich (Klassen-API).frienderlaubt externen Zugriff auf private Daten (vorsichtig verwenden).- Validierung und die Verwendung von
constin Gettern/Settern sind entscheidend. - Unveränderliche Objekte erhöhen die Datensicherheit.
- Kapselung ist ein zentrales Prinzip für wartbare und fehlerfreie Software.
- Alle Beispiele sind mit Visual Studio 2022 und GCC 11+ kompatibel.