Elementy instancji a elementy statyczne
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 27 z 104.
Do tej pory każda utworzona przez Ciebie zmienna składowa należała do konkretnego obiektu. Gdy tworzysz dwa obiekty Player, każdy ma własne name i health. Nazywamy je składowymi instancji — istnieją osobno dla każdej instancji klasy.
A co, jeśli potrzebujesz danych współdzielonych przez wszystkie obiekty? Na przykład śledzenia łącznej liczby graczy.
W tym miejscu przydają się składowe statyczne. Składowa statyczna należy do samej klasy, a nie do żadnego konkretnego obiektu.
class Player {
std::string name; // Pole instancji – każdy gracz ma własne
int health; // Pole instancji
static int playerCount; // Pole statyczne – wspólne dla WSZYSTKICH graczy
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Zwiększ, gdy zostanie utworzony dowolny gracz
}
~Player() {
playerCount--; // Zmniejsz, gdy zostanie zniszczony dowolny gracz
}
};Kluczowa różnica: składowe instancji są dostępne za pośrednictwem obiektu, natomiast do składowych statycznych można uzyskać dostęp za pomocą samej nazwy klasy. Pomyśl o składowych instancji jako o „jednej na obiekt”, a o składowych statycznych jako o „jednej na klasę”.
| Składowe instancji | Składowe statyczne |
|---|---|
| Unikalne dla każdego obiektu | Współdzielone przez wszystkie obiekty |
| Tworzone podczas tworzenia obiektu | Istnieją, zanim zostanie utworzony jakikolwiek obiekt |
Dostępne przez obiekt: player.health | Dostępne przez klasę: Player::playerCount |
Elementy statyczne są przydatne w przypadku liczników, wartości konfiguracyjnych lub wszelkich danych, które logicznie należą do klasy, a nie do poszczególnych obiektów.
Wyzwanie
ŁatwyStwórzmy system ewidencji produktów, który śledzi zarówno szczegóły poszczególnych produktów, jak i ogólne statystyki zapasów, używając składowych instancji i statycznych.
Utworzysz dwa pliki, aby uporządkować swój kod:
Product.h: Zdefiniuj klasęProduct, która zarządza poszczególnymi produktami, a także śledzi dane dotyczące całego stanu zapasów. Twoja klasa powinna zawierać:- Składowe instancji:
name(string) iprice(double): unikalne dla każdego produktu - Składową statyczną
totalProducts, która zlicza, ile produktów aktualnie istnieje - Składową statyczną
totalValue, która śledzi łączną cenę wszystkich produktów - Konstruktor, który przyjmuje nazwę i cenę, inicjalizuje składowe instancji oraz aktualizuje oba liczniki statyczne (zwiększa liczbę, dodaje cenę do łącznej wartości)
- Destruktor, który aktualizuje liczniki statyczne po usunięciu produktu (zmniejsza liczbę, odejmuje cenę od łącznej wartości)
- Metodę
getInfo(), która zwraca ciąg znaków w formacie:"<name>: $<price>" - Metodę statyczną
getInventoryStats(), która zwraca ciąg znaków:"Products: <count>, Total Value: $<value>"
- Składowe instancji:
main.cpp: Pokaż, jak składowe statyczne są współdzielone przez wszystkie obiekty, podczas gdy składowe instancji pozostają unikalne. Wczytaj z wejścia nazwy dwóch produktów i ich ceny (name1, price1, name2, price2: każda wartość w osobnym wierszu), a następnie:- Wyświetl początkowe statystyki zapasów, używając nazwy klasy:
Product::getInventoryStats() - Utwórz blok zakresu z nawiasami klamrowymi, a w nim utwórz obiekt
Productz pierwszą nazwą i ceną. Wyświetl jego informacje i bieżące statystyki zapasów. - Po zakończeniu bloku (zniszczeniu pierwszego produktu) wyświetl
"After first scope:", a następnie statystyki zapasów - Utwórz kolejny obiekt
Productz drugą nazwą i ceną. Wyświetl jego informacje i statystyki zapasów. - Utwórz trzeci obiekt
Producto nazwie"Bonus"i cenie5.00. Wyświetl końcowe statystyki zapasów.
- Wyświetl początkowe statystyki zapasów, używając nazwy klasy:
Pamiętaj, aby zdefiniować składowe statyczne poza klasą w pliku nagłówkowym (po definicji klasy). Formatuj ceny, używając dwóch miejsc po przecinku za pomocą std::fixed i std::setprecision(2) z <iomanip>.
Dołącz plik nagłówkowy w main.cpp, używając #include "Product.h".
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "Product.h"
using namespace std;
int main() {
// Wczytaj dane wejściowe
string name1;
double price1;
string name2;
double price2;
getline(cin, name1);
cin >> price1;
cin.ignore();
getline(cin, name2);
cin >> price2;
// TODO: Wyświetl początkowe statystyki stanu magazynowego, używając Product::getInventoryStats()
// TODO: Utwórz blok o zasięgu ograniczonym nawiasami klamrowymi
// Wewnątrz bloku:
// - Utwórz obiekt Product z name1 i price1
// - Wyświetl informacje o nim, używając getInfo()
// - Wyświetl bieżące statystyki stanu magazynowego
// TODO: Po zakończeniu bloku wyświetl "After first scope:"
// Następnie wyświetl statystyki stanu magazynowego
// TODO: Utwórz kolejny obiekt Product z name2 i price2
// Wyświetl informacje o nim oraz statystyki stanu magazynowego
// TODO: Utwórz trzeci obiekt Product o nazwie "Bonus" i cenie 5.00
// Wypisz końcowe statystyki stanu magazynowego
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