r15.pdf

(244 KB) Pobierz
Szablon dla tlumaczy
Rozdział 15.
Specjalne klasy i funkcje
C++ oferuje kilka sposobów na ograniczenie zakresu i oddziaływania zmiennych i wskaźników.
Do tej pory, dowiedzieliśmy się, jak tworzyć zmienne globalne, lokalne zmienne funkcji,
wskaźniki do zmiennych oraz zmienne składowe klas.
Z tego rozdziału dowiesz się:
czym są zmienne statyczne i funkcje składowe,
jak używać zmiennych statycznych i statycznych funkcji składowych,
jak tworzyć i operować wskaźnikami do funkcji i wskaźnikami do funkcji składowych,
jak pracować z tablicami wskaźników do funkcji.
Statyczne dane składowe
Prawdopodobnie do tej pory uważałeś dane każdego obiektu za unikalne dla tego obiektu (i nie
współużytkowane pomiędzy obiektami klasy). Gdybyś miał na przykład pięć obiektów klasy Cat ,
każdy z nich miałby swój wiek, wagę, itp. Wiek jednego kota nie wpływa na wiek innego.
Czasem zdarza się jednak, że chcemy śledzić pulę danych. Na przykład, możemy chcieć wiedzieć,
ile obiektów danej klasy zostało stworzonych w programie, a także ile z nich istnieje nadal.
Statyczne zmienne składowe są współużytkowane przez wszystkie egzemplarze obiektów klasy.
Stanowią one kompromis pomiędzy danymi globalnymi, które są dostępne dla wszystkich części
programu, a danymi składowymi, które zwykle są dostępne tylko dla konkretnego obiektu.
Statyczne składowe można traktować jako należące do całej klasy, a nie tylko do pojedynczego
obiektu. Zwykła dana składowa odnosi się do pojedynczego obiektu, a dana składowa statyczna
odnosi się do całej klasy. Listing 15.1 deklaruje obiekt Cat , zawierający statyczną składową
HowManyCats (ile kotów). Ta zmienna śledzi, ile obiektów klasy Cat zostało utworzonych.
Śledzenie odbywa się poprzez inkrementację statycznej zmiennej HowManyCats w konstruktorze
klasy i dekrementowanie jej w destruktorze.
Listing 15.1. Statyczne dane składowe
0: //Listing 15.1 Statyczne dane składowe
1:
2: #include <iostream>
3: using namespace std;
4:
5: class Cat
6: {
7: public:
8: Cat(int age):itsAge(age){HowManyCats++; }
9: virtual ~Cat() { HowManyCats--; }
10: virtual int GetAge() { return itsAge; }
11: virtual void SetAge(int age) { itsAge = age; }
12: static int HowManyCats;
13:
14: private:
15: int itsAge;
16:
17: };
18:
19: int Cat::HowManyCats = 0;
20:
21: int main()
22: {
23: const int MaxCats = 5; int i;
24: Cat *CatHouse[MaxCats];
25: for (i = 0; i<MaxCats; i++)
26: CatHouse[i] = new Cat(i);
27:
28: for (i = 0; i<MaxCats; i++)
29: {
30: cout << "Zostalo kotow: ";
31: cout << Cat::HowManyCats;
32: cout << "\n";
33: cout << "Usuwamy kota, ktory ma ";
34: cout << CatHouse[i]->GetAge();
35: cout << " lat\n";
36: delete CatHouse[i];
37: CatHouse[i] = 0;
38: }
39: return 0;
40: }
Wynik
Zostalo kotow: 5
Usuwamy kota, ktory ma 0 lat
Zostalo kotow: 4
Usuwamy kota, ktory ma 1 lat
Zostalo kotow: 3
Usuwamy kota, ktory ma 2 lat
Zostalo kotow: 2
Usuwamy kota, ktory ma 3 lat
Zostalo kotow: 1
Usuwamy kota, ktory ma 4 lat
Analiza
W liniach od 5. do 17. została zadeklarowana uproszczona klasa Cat . W linii 12. zmienna
HowManyCats została zadeklarowana jako statyczna zmienna składowa typu int .
Sama deklaracja zmiennej HowManyCats nie definiuje wartości całkowitej i nie jest dla niej
rezerwowane miejsce w pamięci. W odróżnieniu od zwykłych zmiennych składowych, w
momencie tworzenia egzemplarzy obiektów klasy Cat , nie jest tworzone miejsce dla tej zmiennej
statycznej, gdyż nie znajduje się ona w obiekcie. W związku z tym musieliśmy zdefiniować i
zainicjalizować tę zmienną w linii 19..
Programistom bardzo często zdarza się zapomnieć o zdefiniowaniu statycznych zmiennych
składowych klasy. Nie pozwól, by przydarzało się to tobie! Oczywiście, gdy się przydarzy, linker
zgłosi komunikat błędu, informujący o niezdefiniowanym symbolu, na przykład taki jak poniższy:
undefined symbol Cat::HowManyCats
(niezdefiniowany symbol Cat::HowManyCats)
Nie musimy definiować zmiennej itsAge , gdyż nie jest statyczną zmienną składową i w związku
z tym jest definiowana za każdym razem, gdy tworzymy obiekt klasy Cat (w tym przypadku w
linii 26. programu).
Konstruktor klasy Cat w linii 8. inkrementuje statyczną zmienną składową. Destruktor (zawarty w
linii 9.) dekrementuje ją. Zatem zmienna HowManyCats przez cały czas zawiera właściwą ilość
obiektów Cat , które zostały utworzone i jeszcze nie zniszczone.
Program sterujący. zawarty w liniach od 21. do 40., tworzy pięć egzemplarzy obiektów klasy Cat
i umieszcza je w pamięci. Powoduje to pięciokrotne wywołanie konstruktora, w związku z czym
następuje pięciokrotne inkrementowanie zmiennej HowManyCats od jej początkowej wartości 0 .
Następnie program w pętli przechodzi przez wszystkie pięć elementów tablicy i przed usunięciem
kolejnego wskaźnika do obiektu Cat wypisuje wartość zmiennej HowManyCats . Wydruk
pokazuje to, że wartością początkową jest 5 (gdyż zostało skonstruowanych pięć obiektów) i że
przy każdym wykonaniu pętli pozostaje o jeden obiekt Cat mniej.
Zwróć uwagę, że zmienna HowManyCats jest publiczna i jest używana bezpośrednio w funkcji
main() . Nie ma powodu do udostępniania zmiennej składowej w ten sposób. Najlepszą metodą
jest uczynienie z niej prywatnej składowej i udostępnienie publicznego akcesora (o ile ma być ona
dostępna wyłącznie poprzez egzemplarze klasy Cat ). Z drugiej strony, gdybyśmy chcieli
korzystać z tej danej bezpośrednio, niekoniecznie posiadając obiekt klasy Cat , mamy do wyboru
dwie opcje: możemy zadeklarować tę zmienną jako publiczną, tak jak pokazano na listingu 15.2,
albo dostarczyć akcesor w postaci statycznej funkcji składowej, co zostanie omówione w dalszej
części rozdziału.
Listing 15.2. Dostęp do statycznych danych składowych bez obiektu
0: //Listing 15.2 Statyczne dane składowe
1:
2: #include <iostream>
3: using namespace std;
4:
5: class Cat
6: {
7: public:
8: Cat(int age):itsAge(age){HowManyCats++; }
9: virtual ~Cat() { HowManyCats--; }
10: virtual int GetAge() { return itsAge; }
11: virtual void SetAge(int age) { itsAge = age; }
12: static int HowManyCats;
13:
14: private:
15: int itsAge;
16:
17: };
18:
19: int Cat::HowManyCats = 0;
20:
21: void TelepathicFunction();
22:
23: int main()
24: {
25: const int MaxCats = 5; int i;
26: Cat *CatHouse[MaxCats];
27: for (i = 0; i<MaxCats; i++)
28: {
29: CatHouse[i] = new Cat(i);
30: TelepathicFunction();
31: }
32:
33: for ( i = 0; i<MaxCats; i++)
34: {
35: delete CatHouse[i];
36: TelepathicFunction();
37: }
38: return 0;
39: }
40:
41: void TelepathicFunction()
42: {
43: cout << "Zostalo jeszcze zywych kotow: ";
44: cout << Cat::HowManyCats << "\n";
45: }
Wynik
Zostalo jeszcze zywych kotow: 1
Zostalo jeszcze zywych kotow: 2
Zostalo jeszcze zywych kotow: 3
Zostalo jeszcze zywych kotow: 4
Zostalo jeszcze zywych kotow: 5
Zostalo jeszcze zywych kotow: 4
Zostalo jeszcze zywych kotow: 3
Zostalo jeszcze zywych kotow: 2
Zostalo jeszcze zywych kotow: 1
Zostalo jeszcze zywych kotow: 0
Analiza
Zgłoś jeśli naruszono regulamin