Metody i zmienne statyczne
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 31 z 104.
Wiesz już, że składowe statyczne są współdzielone przez wszystkie obiekty. Teraz przyjrzyjmy się, jak prawidłowo definiować i używać metod statycznych razem ze zmiennymi statycznymi.
Zmienne statyczne zadeklarowane wewnątrz klasy muszą być definiowane poza klasą, zazwyczaj w pliku źródłowym. Dzieje się tak, ponieważ składowe statyczne potrzebują dokładnie jednego miejsca przechowywania współdzielonego przez wszystkie obiekty:
class Counter {
static int count; // Tylko deklaracja
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { // Metoda statyczna
return count;
}
};
// Definicja – wymagana poza klasą
int Counter::count = 0;Metoda statyczna należy do klasy, a nie do żadnego obiektu. Ma to ważną konsekwencję: metody statyczne nie mogą uzyskiwać dostępu do składowych instancji ani używać wskaźnika this, ponieważ nie są wywoływane na żadnym konkretnym obiekcie.
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // Może uzyskiwać dostęp do składowych statycznych
}
};
double MathUtils::pi = 3.14159;
// Wywoływana bez obiektu
double area = MathUtils::circleArea(5.0);Metody statyczne są idealne do funkcji pomocniczych, które nie wymagają stanu obiektu, metod fabrykujących tworzących obiekty lub uzyskiwania dostępu do danych statycznych. Ponieważ nie wymagają instancji obiektu, wywołujesz je, używając nazwy klasy i operatora rozstrzygania zakresu: ClassName::methodName().
Wyzwanie
ŁatwyZbudujmy system generowania unikalnych identyfikatorów, który pokazuje, jak metody i zmienne statyczne współpracują, zapewniając funkcjonalność na poziomie klasy bez potrzeby tworzenia jej obiektów.
Utworzysz dwa pliki, aby uporządkować swój kod:
IDGenerator.h: Zdefiniuj klasęIDGenerator, która generuje kolejne unikalne identyfikatory. Twoja klasa powinna zawierać:- Prywatny statyczny składowy
nextId, który śledzi kolejny identyfikator do przypisania (zaczyna od1000) - Prywatny statyczny składowy
prefix(łańcuch znaków), który przechowuje konfigurowalny prefiks dla wszystkich identyfikatorów - Metodę statyczną
setPrefix(const std::string& p), która zmienia prefiks - Metodę statyczną
getNextId(), która zwraca łańcuch znaków łączący prefiks z bieżącym numerem identyfikatora, a następnie zwiększa wartośćnextIdna potrzeby następnego wywołania - Metodę statyczną
peekNextId(), która zwraca wartość następnego identyfikatora bez zwiększania licznika - Metodę statyczną
getGeneratedCount(), która zwraca liczbę wygenerowanych identyfikatorów (podpowiedź: oblicz ją na podstawie wartości początkowej i bieżącej wartościnextId) - Metodę statyczną
reset(), która ustawia wartośćnextIdz powrotem na1000
Pamiętaj, aby zdefiniować składowe statyczne poza klasą, po definicji klasy. Zainicjuj
prefixwartością"ID-".- Prywatny statyczny składowy
main.cpp: Pokaż wywoływanie metod statycznych za pomocą nazwy klasy, bez tworzenia żadnych obiektów. Wczytaj niestandardowy prefiks z wejścia, a następnie:- Wyświetl
"Peek: <peeked_id>", używającpeekNextId() - Wygeneruj trzy identyfikatory za pomocą
getNextId()i wyświetl każdy z nich jako"Generated: <id>" - Wyświetl
"Count: <count>", pokazując liczbę wygenerowanych identyfikatorów - Zmień prefiks, używając wczytanej wartości i
setPrefix() - Wygeneruj dwa kolejne identyfikatory i wyświetl każdy z nich jako
"Generated: <id>" - Ponownie wyświetl
"Count: <count>" - Wywołaj
reset() - Wyświetl
"After reset - Peek: <peeked_id>" - Wyświetl
"After reset - Count: <count>"
- Wyświetl
Zauważ, że nigdy nie tworzysz obiektu IDGenerator: wszystkie metody są wywoływane bezpośrednio na klasie za pomocą IDGenerator::methodName(). To kluczowa cecha metod statycznych: należą do samej klasy, a nie do żadnej konkretnej instancji.
Dołącz <string> i <iostream> w pliku nagłówkowym i nie zapomnij o strażnikach nagłówka.
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// Wczytaj niestandardowy prefiks z wejścia
string customPrefix;
cin >> customPrefix;
// TODO: Wypisz "Peek: <peeked_id>" za pomocą peekNextId()
// TODO: Wygeneruj trzy identyfikatory za pomocą getNextId() i wypisz każdy w formacie "Generated: <id>"
// TODO: Wypisz "Count: <count>", pokazując, ile identyfikatorów wygenerowano
// TODO: Zmień prefiks na wartość z wejścia za pomocą setPrefix()
// TODO: Wygeneruj jeszcze dwa identyfikatory i wypisz każdy w formacie "Generated: <id>"
// TODO: Ponownie wypisz "Count: <count>"
// TODO: Wywołaj reset()
// TODO: Wypisz "After reset - Peek: <peeked_id>"
// TODO: Wypisz "After reset - Count: <count>"
return 0;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online