Zugriffsbezeichner im Detail
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 35 von 104.
Nachdem du nun die drei Zugriffsbezeichner verstanden hast, wollen wir untersuchen, wie sie sich verhalten, wenn du mehrere Objekte derselben Klasse hast. Ein häufiges Missverständnis besteht darin, dass private „nur dieses Objekt“ bedeutet – tatsächlich bedeutet es jedoch „nur diese Klasse“.
Objekte derselben Klasse können auf die privaten Member des jeweils anderen zugreifen:
class Person {
std::string secret;
public:
Person(std::string s) : secret(s) {}
void readSecret(const Person& other) {
// Zugriff auf das private Member eines anderen Objekts – erlaubt!
std::cout << other.secret;
}
};Das funktioniert, weil die Zugriffskontrolle auf Klassenebene und nicht auf Objektebene durchgesetzt wird. Die Methode readSecret ist Teil der Klasse Person und kann daher auf private Mitglieder jedes Person-Objekts zugreifen. Dieses Design ermöglicht es Operationen wie Kopierkonstruktoren und Vergleichsoperatoren, mit dem internen Zustand anderer Objekte zu arbeiten.
Du kannst auch innerhalb einer Klasse mehrmals zwischen Zugriffsbezeichnern wechseln:
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // Zurück zu public
private:
void privateHelper(); // Wieder private
};Obwohl dies gültiges C++ ist, ist es im Allgemeinen besser, Member zur besseren Lesbarkeit nach Zugriffsebene zu gruppieren. Die meisten Styleguides empfehlen, öffentliche Member zuerst aufzulisten (da sie die Klassenschnittstelle bilden), gefolgt von geschützten und dann privaten Membern.
Aufgabe
EinfachErstellen wir ein Wallet-Vergleichssystem, das veranschaulicht, wie Objekte derselben Klasse auf die privaten Member der jeweils anderen Objekte zugreifen können. Dies ist eine wichtige Erkenntnis über die Zugriffskontrolle in C++: Sie wird auf Klassenebene durchgesetzt, nicht auf Objektebene.
Du erstellst zwei Dateien, um deinen Code zu organisieren:
Wallet.h: Definiere eineWallet-Klasse, die private Finanzdaten speichert, aber Vergleiche zwischen Wallets ermöglicht. Deine Klasse sollte Folgendes enthalten:- Private Member:
ownerName(String) undbalance(Double) - Einen Konstruktor, der den Namen des Eigentümers und das Anfangsguthaben entgegennimmt
- Einen öffentlichen Getter
getOwnerName(), der den Namen des Eigentümers zurückgibt - Eine Methode
hasMoreThan(const Wallet& other), die das Guthaben dieses Wallets mit dem privaten Guthaben eines anderen Wallets vergleicht undtruezurückgibt, wenn dieses Wallet mehr Geld hat - Eine Methode
combinedBalance(const Wallet& other), die die Summe der privaten Guthaben beider Wallets zurückgibt - Eine Methode
transferTo(Wallet& other, double amount), die Geld von diesem Wallet auf ein anderes überträgt. Sie sollte die privaten Guthaben beider Wallets direkt ändern (nur wenn der Betrag positiv ist und das Guthaben dieses Wallets nicht übersteigt)
- Private Member:
main.cpp: Veranschauliche den objektübergreifenden Zugriff auf private Member. Lies zwei Eigentümernamen und zwei Guthaben aus der Eingabe ein (vier Zeilen: name1, balance1, name2, balance2), und führe dann Folgendes aus:- Erstelle zwei
Wallet-Objekte mit den Eingabewerten - Gib
"Combined wealth: $<amount>"mithilfe voncombinedBalance()aus - Vergleiche die Wallets und gib für den Eigentümer mit dem höheren Guthaben
"<name> has more money"aus (verwendehasMoreThan(), um dies zu bestimmen) - Übertrage mit
100.0transferTo()vom ersten Wallet auf das zweite - Gib
"After transfer:"aus - Gib erneut
"Combined wealth: $<amount>"aus (sollte unverändert sein) - Vergleiche erneut und gib
"<name> has more money"aus (das Ergebnis kann sich geändert haben)
- Erstelle zwei
Das zentrale Konzept hierbei ist, dass Methoden wie hasMoreThan() und transferTo() direkt auf das private Wallet-Member eines anderen balance-Objekts zugreifen können: Getter sind nicht erforderlich. Dies funktioniert, weil die Zugriffskontrolle in C++ klassenbasiert ist: Jeder Code innerhalb der Wallet-Klasse kann auf private Member von jedem Wallet-Objekt zugreifen.
Formatiere alle Geldbeträge mit zwei Dezimalstellen mithilfe von std::fixed und std::setprecision(2) aus <iomanip>. Konvertiere die Guthabeneingaben mithilfe von std::stod().
Probier es selbst
#include <iostream>
#include <string>
#include <iomanip>
#include "Wallet.h"
using namespace std;
int main() {
// Eingabe lesen: name1, balance1, name2, balance2
string name1, name2;
string balanceStr1, balanceStr2;
getline(cin, name1);
getline(cin, balanceStr1);
getline(cin, name2);
getline(cin, balanceStr2);
double balance1 = stod(balanceStr1);
double balance2 = stod(balanceStr2);
// Ausgabeformatierung für Geldbeträge festlegen
cout << fixed << setprecision(2);
// TODO: Erstelle zwei Wallet-Objekte mit den Eingabewerten
// TODO: Print combined wealth using combinedBalance()
// Format: "Combined wealth: $<amount>"
// TODO: Compare wallets using hasMoreThan() and print who has more money
// Format: "<name> has more money"
// TODO: Überweise 100.0 vom ersten Wallet zum zweiten mit transferTo()
// TODO: Print "After transfer:"
// TODO: Print combined wealth again
// TODO: Compare again and print who has more money
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamespaces & GültigkeitsbereichEinführung in OOP mit C++Klassen vs. ObjekteDer „this“-ZeigerMethoden (Member-Funktionen)Attribute (Datenmember)Grundlagen zu Ctors & DtorsRückblick – Einfacher Taschenrechner4Klassenattribute
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen und -KlassenZusammenfassung – Bankkontoverwaltung7Vererbung
Grundlagen der VererbungZugriffsebenen bei der VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick – Mitarbeiterhierarchie2Speicherverwaltung
Stack- vs. Heap-SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Intelligente Zeiger in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsbezeichner in C++Zugriffsbezeichner im DetailInformationsverbergungStruct vs. KlasseVerschachtelte und innere KlassenWiederholung – Studierendenverwaltungssystem8Polymorphie
Polymorphie zur Compilezeit vs. LaufzeitFunktionsüberladungVirtuelle Funktionen erneut betrachtetRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIRückblick – Shape-Calculator3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorMove-KonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktor im DetailDrei-/Fünf-/Null-RegelZusammenfassung – String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladung der Operatoren [] und ()TypkonvertierungsoperatorenWiederholung – Matrix-Klasse9Templates
FunktionstemplatesKlassen-TemplatesTemplate-SpezialisierungVariadische TemplatesGrundlagen zu SFINAE und Type TraitsRückblick – Generischer ContainerÜbe selbstständig: Online-C++-Compiler