Statische Methoden und Variablen
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 31 von 104.
Sie haben gelernt, dass statische Member über alle Objekte hinweg geteilt werden. Lassen Sie uns nun untersuchen, 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, normalerweise in einer Quelldatei. Dies liegt daran, 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-Pointer verwenden, da sie nicht für ein 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;
// Aufruf ohne Objekt
double area = MathUtils::circleArea(5.0);Statische Methoden sind ideal für Hilfsfunktionen, die keinen Objektzustand benötigen, Factory-Methoden, die Objekte erstellen, oder den Zugriff auf statische Daten. Da sie keine Objektinstanz erfordern, rufen Sie sie unter Verwendung des Klassennamens und des Bereichsauflösungsoperators auf: ClassName::methodName().
Aufgabe
EinfachLassen Sie uns ein System zur Generierung eindeutiger IDs erstellen, das demonstriert, wie statische Methoden und Variablen zusammenarbeiten, um Funktionalität auf Klassenebene bereitzustellen, ohne dass Objektinstanzen benötigt werden.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
IDGenerator.h: Definieren Sie eine KlasseIDGenerator, die sequenzielle eindeutige IDs generiert. Ihre Klasse sollte Folgendes enthalten:- Ein privates statisches Mitglied
nextId, das die nächste zuzuweisende ID verfolgt (beginnt bei1000) - Ein privates statisches Mitglied
prefix(String), 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 einen String zurückgibt, der das Präfix und die aktuelle ID-Nummer kombiniert, und dannnextIdfür den nächsten Aufruf inkrementiert - Eine statische Methode
peekNextId(), die zurückgibt, wie die nächste ID aussehen würde, ohne den Zähler zu inkrementieren - Eine statische Methode
getGeneratedCount(), die zurückgibt, wie viele IDs generiert wurden (Hinweis: Berechnen Sie dies aus dem Startwert und der aktuellennextId) - Eine statische Methode
reset(), dienextIdwieder auf1000zurücksetzt
Denken Sie daran, Ihre statischen Mitglieder außerhalb der Klasse nach der Klassendefinition zu definieren. Initialisieren Sie
prefixmit"ID-".- Ein privates statisches Mitglied
main.cpp: Demonstrieren Sie den Aufruf statischer Methoden unter Verwendung des Klassennamens, ohne Objekte zu erstellen. Lesen Sie ein benutzerdefiniertes Präfix aus der Eingabe und führen Sie dann Folgendes aus:- Geben Sie
"Peek: <peeked_id>"unter Verwendung vonpeekNextId()aus - Generieren Sie drei IDs mit
getNextId()und geben Sie jede als"Generated: <id>"aus - Geben Sie
"Count: <count>"aus, um anzuzeigen, wie viele IDs generiert wurden - Ändern Sie das Präfix mit dem Eingabewert über
setPrefix() - Generieren Sie zwei weitere IDs und geben Sie jede als
"Generated: <id>"aus - Geben Sie erneut
"Count: <count>"aus - Rufen Sie
reset()auf - Geben Sie
"After reset - Peek: <peeked_id>"aus - Geben Sie
"After reset - Count: <count>"aus
- Geben Sie
Beachten Sie, dass Sie niemals ein IDGenerator-Objekt erstellen — alle Methoden werden direkt auf der Klasse mit IDGenerator::methodName() aufgerufen. Dies ist das Hauptmerkmal statischer Methoden: Sie gehören zur Klasse selbst und nicht zu einer bestimmten Instanz.
Binden Sie <string> und <iostream> in Ihre Header-Datei ein und vergessen Sie die Header-Guards nicht.
Spickzettel
Statische Variablen, die innerhalb einer Klasse deklariert werden, müssen außerhalb der Klasse definiert werden. Statische Member benötigen genau einen Speicherort, der von allen Objekten geteilt wird:
class Counter {
static int count; // Nur Deklaration
public:
Counter() { count++; }
static int getCount() {
return count;
}
};
// Definition - außerhalb der Klasse erforderlich
int Counter::count = 0;Eine statische Methode gehört zur Klasse, nicht zu einem Objekt. Statische Methoden können nicht auf Instanz-Member zugreifen oder den this-Pointer verwenden, da sie nicht für ein 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;
// Aufruf ohne Objekt unter Verwendung des Klassennamens
double area = MathUtils::circleArea(5.0);Statische Methoden werden unter Verwendung des Klassennamens und des Bereichsauflösungsoperators aufgerufen: ClassName::methodName(). Sie sind ideal für Hilfsfunktionen, die keinen Objektzustand benötigen, Factory-Methoden oder den Zugriff auf statische Daten.
Probier es selbst
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// Benutzerdefiniertes Präfix von der Eingabe einlesen
string customPrefix;
cin >> customPrefix;
// TODO: "Peek: <peeked_id>" mit peekNextId() ausgeben
// TODO: Drei IDs mit getNextId() generieren und jede als "Generated: <id>" ausgeben
// TODO: "Count: <count>" ausgeben, um anzuzeigen, wie viele IDs generiert wurden
// TODO: Das Präfix unter Verwendung des Eingabewerts mit setPrefix() ändern
// TODO: Zwei weitere IDs generieren und jede als "Generated: <id>" ausgeben
// TODO: "Count: <count>" erneut ausgeben
// TODO: reset() aufrufen
// TODO: "After reset - Peek: <peeked_id>" ausgeben
// TODO: "After reset - Count: <count>" 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 & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container