Instanz- vs. statische Member
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 27 von 104.
Bisher gehört jede von dir erstellte Membervariable zu einem bestimmten Objekt. Wenn du zwei Player-Objekte erstellst, hat jedes seinen eigenen name- und health-Wert. Diese werden als Instanzmember bezeichnet – sie existieren für jede Instanz der Klasse separat.
Aber was, wenn du Daten benötigst, die von allen Objekten gemeinsam genutzt werden? Zum Beispiel, um zu verfolgen, wie viele Spieler insgesamt existieren.
Hier kommen statische Member ins Spiel. Ein statisches Member gehört zur Klasse selbst, nicht zu einem bestimmten Objekt.
class Player {
std::string name; // Instanzmitglied - jeder Spieler hat sein eigenes
int health; // Instanzmitglied
static int playerCount; // Statisches Mitglied - von ALLEN Spielern geteilt
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Erhöhen, wenn ein Spieler erstellt wird
}
~Player() {
playerCount--; // Verringern, wenn ein Spieler zerstört wird
}
};Der entscheidende Unterschied: Auf Instanzmitglieder wird über ein Objekt zugegriffen, während auf statische Mitglieder über den Klassennamen selbst zugegriffen werden kann. Betrachte Instanzmitglieder als „eines pro Objekt“ und statische Mitglieder als „eines pro Klasse“.
| Instanzmitglieder | Statische Mitglieder |
|---|---|
| Für jedes Objekt einzigartig | Über alle Objekte hinweg geteilt |
| Werden erstellt, wenn das Objekt erstellt wird | Existieren, bevor ein Objekt erstellt wird |
Zugriff über das Objekt: player.health | Zugriff über die Klasse: Player::playerCount |
Statische Member sind nützlich für Zähler, Konfigurationswerte oder beliebige Daten, die logisch zur Klasse und nicht zu einzelnen Objekten gehören.
Aufgabe
EinfachErstellen wir ein Produktinventarsystem, das sowohl Details einzelner Produkte als auch allgemeine Inventarstatistiken mithilfe von Instanz- und statischen Membern erfasst.
Du wirst zwei Dateien erstellen, um deinen Code zu organisieren:
Product.h: Definiere eineProduct-Klasse, die einzelne Produkte verwaltet und gleichzeitig Daten für das gesamte Inventar erfasst. Deine Klasse sollte Folgendes enthalten:- Instanzmember:
name(String) undprice(double): für jedes Produkt einzigartig - Ein statisches Member
totalProducts, das zählt, wie viele Produkte derzeit existieren - Ein statisches Member
totalValue, das den Gesamtpreis aller Produkte erfasst - Einen Konstruktor, der einen Namen und einen Preis entgegennimmt, die Instanzmember initialisiert und beide statischen Zähler aktualisiert (Anzahl erhöhen, Preis zum Gesamtwert addieren)
- Einen Destruktor, der die statischen Zähler aktualisiert, wenn ein Produkt entfernt wird (Anzahl verringern, Preis vom Gesamtwert abziehen)
- Eine
getInfo()-Methode, die einen String im folgenden Format zurückgibt:"<name>: $<price>" - Eine statische Methode
getInventoryStats(), die einen String zurückgibt:"Products: <count>, Total Value: $<value>"
- Instanzmember:
main.cpp: Zeige, wie statische Member von allen Objekten gemeinsam genutzt werden, während Instanzmember einzigartig bleiben. Lies zwei Produktnamen und deren Preise aus der Eingabe ein (name1, price1, name2, price2: jeweils in einer eigenen Zeile), und:- Gib die anfänglichen Inventarstatistiken mithilfe des Klassennamens aus:
Product::getInventoryStats() - Erstelle mit geschweiften Klammern einen Gültigkeitsbereich und darin ein
Productmit dem ersten Namen und Preis. Gib dessen Informationen und die aktuellen Inventarstatistiken aus. - Nachdem der Block endet (das erste Produkt zerstört wurde), gib
"After first scope:"gefolgt von den Inventarstatistiken aus - Erstelle ein weiteres
Productmit dem zweiten Namen und Preis. Gib dessen Informationen und die Inventarstatistiken aus. - Erstelle ein drittes
Productmit dem Namen"Bonus"und dem Preis5.00. Gib die abschließenden Inventarstatistiken aus.
- Gib die anfänglichen Inventarstatistiken mithilfe des Klassennamens aus:
Denke daran, deine statischen Member außerhalb der Klasse in der Header-Datei zu definieren (nach der Klassendefinition). Formatiere Preise mit zwei Dezimalstellen mithilfe von std::fixed und std::setprecision(2) aus <iomanip>.
Binde deine Header-Datei in main.cpp mithilfe von #include "Product.h" ein.
Probier es selbst
#include <iostream>
#include <string>
#include "Product.h"
using namespace std;
int main() {
// Eingabe lesen
string name1;
double price1;
string name2;
double price2;
getline(cin, name1);
cin >> price1;
cin.ignore();
getline(cin, name2);
cin >> price2;
// TODO: Initiale Inventarstatistiken mit Product::getInventoryStats() ausgeben
// TODO: Einen Scope-Block mit geschweiften Klammern erstellen
// Innerhalb des Blocks:
// - Ein Product mit name1 und price1 erstellen
// - Seine Info mit getInfo() ausgeben
// - Aktuelle Inventarstatistiken ausgeben
// TODO: After the block ends, print "After first scope:"
// Dann die Inventarstatistiken ausgeben
// TODO: Ein weiteres Product mit name2 und price2 erstellen
// Seine Info und die Inventarstatistiken ausgeben
// TODO: Ein drittes Product mit dem Namen "Bonus" und dem Preis 5.00 erstellen
// Die finalen Inventarstatistiken ausgeben
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