Statische Methoden und Variablen
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 31 von 104.
Du hast gelernt, dass statische Member von allen Objekten gemeinsam genutzt werden. Sehen wir uns nun an, wie man statische Methoden zusammen mit statischen Variablen richtig definiert und verwendet.
Statische Variablen, die innerhalb einer Klasse deklariert werden, müssen außerhalb der Klasse definiert werden, typischerweise in einer Quelldatei. Der Grund dafür ist, dass statische Member genau einen Speicherort benötigen, der von allen Objekten gemeinsam genutzt wird:
class Counter {
static int count; // Nur Deklaration
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { // Statische Methode
return count;
}
};
// Definition – außerhalb der Klasse erforderlich
int Counter::count = 0;Eine statische Methode gehört zur Klasse, nicht zu einem Objekt. Dies hat eine wichtige Konsequenz: Statische Methoden können nicht auf Instanzmitglieder zugreifen oder den this-Zeiger verwenden, da sie für kein bestimmtes Objekt aufgerufen werden.
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // Kann auf statische Member zugreifen
}
};
double MathUtils::pi = 3.14159;
// Wird ohne ein Objekt aufgerufen
double area = MathUtils::circleArea(5.0);Statische Methoden eignen sich ideal für Hilfsfunktionen, die keinen Objektzustand benötigen, für Factory-Methoden, die Objekte erstellen, oder für den Zugriff auf statische Daten. Da sie keine Objektinstanz erfordern, rufst du sie mithilfe des Klassennamens und des Operators zur Bereichsauflösung auf: ClassName::methodName().
Aufgabe
EinfachErstellen wir ein System zur Generierung eindeutiger IDs, das demonstriert, wie statische Methoden und Variablen zusammenarbeiten, um Funktionalität auf Klassenebene bereitzustellen, ohne Objektinstanzen zu benötigen.
Du wirst zwei Dateien erstellen, um deinen Code zu organisieren:
IDGenerator.h: Definiere eineIDGenerator-Klasse, die fortlaufende eindeutige IDs generiert. Deine Klasse sollte Folgendes enthalten:- Ein privates statisches Mitglied
nextId, das die nächste zu vergebende ID verfolgt (beginnt bei1000) - Ein privates statisches Mitglied
prefix(Zeichenkette), das ein anpassbares Präfix für alle IDs speichert - Eine statische Methode
setPrefix(const std::string& p), die das Präfix ändert - Eine statische Methode
getNextId(), die eine Zeichenkette zurückgibt, die das Präfix und die aktuelle ID-Nummer kombiniert, und anschließendnextIdfür den nächsten Aufruf erhöht - Eine statische Methode
peekNextId(), die angibt, wie die nächste ID aussehen würde, ohne den Zähler zu erhöhen - Eine statische Methode
getGeneratedCount(), die zurückgibt, wie viele IDs generiert wurden (Hinweis: Berechne dies aus dem Startwert und dem aktuellen Wert vonnextId) - Eine statische Methode
reset(), dienextIdauf1000zurücksetzt
Denke daran, deine statischen Mitglieder außerhalb der Klasse nach der Klassendefinition zu definieren. Initialisiere
prefixmit"ID-".- Ein privates statisches Mitglied
main.cpp: Demonstriere den Aufruf statischer Methoden mithilfe des Klassennamens, ohne Objekte zu erstellen. Lies ein benutzerdefiniertes Präfix aus der Eingabe ein und:- Gib
"Peek: <peeked_id>"mithilfe vonpeekNextId()aus - Generiere drei IDs mithilfe von
getNextId()und gib jede als"Generated: <id>"aus - Gib
"Count: <count>"aus, um anzuzeigen, wie viele IDs generiert wurden - Ändere das Präfix mithilfe des Eingabewerts mit
setPrefix() - Generiere zwei weitere IDs und gib jede als
"Generated: <id>"aus - Gib erneut
"Count: <count>"aus - Rufe
reset()auf - Gib
"After reset - Peek: <peeked_id>"aus - Gib
"After reset - Count: <count>"aus
- Gib
Beachte, dass du niemals ein IDGenerator-Objekt erstellst: Alle Methoden werden direkt für die Klasse mithilfe von IDGenerator::methodName() aufgerufen. Dies ist das entscheidende Merkmal statischer Methoden: Sie gehören zur Klasse selbst und nicht zu einer bestimmten Instanz.
Binde <string> und <iostream> in deine Header-Datei ein und vergiss die Header-Guards nicht.
Probier es selbst
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// Lese benutzerdefiniertes Präfix aus der Eingabe
string customPrefix;
cin >> customPrefix;
// TODO: Gib "Peek: <peeked_id>" mit peekNextId() aus
// TODO: Generiere drei IDs mit getNextId() und gib jede als "Generated: <id>" aus
// TODO: Gib "Count: <count>" aus und zeige, wie viele IDs generiert wurden
// TODO: Ändere das Präfix mit dem Eingabewert über setPrefix()
// TODO: Generiere zwei weitere IDs und gib jede als "Generated: <id>" aus
// TODO: Gib "Count: <count>" erneut aus
// TODO: Rufe reset() auf
// TODO: Print "After reset - Peek: <peeked_id>"
// TODO: Print "After reset - Count: <count>"
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