Życie pisze najbardziej oryginalne, najbardziej komiczne, a jednocześnie najbardziej dramatyczne scenariusze.
To tyle. Jeśli masz jeszcze jakieś pytania, to najlepiej od razu dodam, że jeszcze
ani raz w żadnym poważnym programie nie użyłem zagnieżdżenia definicji
klas.
13.1 Lokalna definicja klasy
Tutaj mówić będziemy o zagnieżdżeniu definicji klasy, ale nie w innej klasie,
tylko w jakiejś funkcji. Jeśli definicję klasy umieścimy w funkcji, to ma ona
zakres ważności lokalny, ograniczony do bloku tej funkcji.
Podkreślam: wewnątrz funkcji jest definicja klasy, a nie konkretny egzemplarz
jej obiektu.
Nazwa takiej klasy widziana jest tylko w zakresie, w którym jest zdefiniowana,
czyli poza zakresem tej funkcji nie da się kreować obiektów tej klasy, ani nawet
na nich działać.
Funkcje składowe takiej klasy
muszą być zdefiniowane wewnątrz ciała klasy (będą więc inline).
Nie można definicji tych funkcji umieścić poza ciałem klasy bo:
*»* - zaraz za definicją klasy, (czyli jeszcze w funkcji, w której jest ona
lokalną) nie można, bo łamałoby to wspomnianą już w poprzednim
paragrafie zasadę C++, że definicje funkcji nie mogą być zagnieżdżane
w innych funkcjach,
*#* - definicji funkcji składowych tej lokalnej klasy nie można umieścić
w zakresie globalnym, bo tam nazwa tej klasy jest zupełnie nieznana.
Z tych ograniczeń wynika następująca zasada praktyczna: Skoro funkcje
składowe będą inline - to powinny być krótkie.
332 Rozdz. 13 Zagnieżdżona definicja klasy
Lokalna definicja klasy
Klasa lokalna przydaje się wtedy, gdy mamy do czynienia z klasą bardzo
prostą i gdy jej użycie ogranicza się tylko do wnętrza tej jednej jedynej funkcji
w programie.
Lokalna klasa ma zakres ważności wnętrza funkcji, w której się znajduje, więc
może używać zdefiniowanych w niej nazw typów (typedef), typów wylicze-
niowych (enum), zdefiniowanych w niej zmiennych statycznych, a także na/w
zadeklarowanych w niej jako extern.
Strasznie to zawiłe, co? Nie przejmuj się, łatwo to zapamiętać tak:
W klasie tej można używać tego wszystkiego, co już istnieje w czasie kompilacji
oraz linkowania.
• Definicje typów wyliczeniowych (enum) wtedy już istnieją?
Tak, są przecież napisane czarno na białym.
• Instrukcje typedef? - także - kompilator je poznał.
• Nazwy zdeklarowane jako typu extern? Także - kompilator
się z nimi zapoznał i w czasie linkowania już będzie dokładnie
wiadomo, które komórki w pamięci one zajmą.
Skoro tak, to czego nie ma w tym zestawie ?
Zmiennych (obiektów) automatycznych, które najczęściej definiujemy sobie
w funkcjach. One będą bowiem leżały na stosie, więc ich adres jest na etapie
kompilacji i linkowania jest nawet w przybliżeniu nieznany. Spójrz na stos
książek na Twoim biurku - jego wygląd zależy nie tylko od tego, co robisz teraz,
ale także od tego, co robiłeś wczoraj i przedwczoraj.
Kompilator nie może więc wygenerować dla naszej klasy lokalnej kodu, który
sprawi, że zmienną z tej komórki stosu doda się do tamtej, a rezultat złoży się
w jeszcze innej. Zatem:
I
Klasa lokalna w funkcji - nie może używać jej zmiennych auto-
matycznych
Ciekawostki o zasłanianiu
Jeszcze jedna ciekawa rzecz: Jeśli mamy zmienną globalną o nazwie xyz,
a w funkcji zdefiniujemy sobie zmienną automatyczną o takiej samej nazwie
xyz, to zwykle nazwa zmiennej lokalnej automatycznej zasłania nazwę glo-
balną.
Tutaj jednak, w wypadku klasy lokalnej, znowu jest inaczej. Gdy kompilator
pracuje nad definicją lokalnej klasy - nie da się nawet w przybliżeniu określić
wyglądu stosu - zatem kompilator daje to, co może: obiekt globalny. On nie jest
dla klasy lokalnej zasłonięty obiektem automatycznym. Jakiekolwiek odnie-
sienie się od obiektu xyz będzie odniesieniem się do globalnego obiektu xyz.
Próba odniesienia się do jakiejś nazwy, która jest tylko lokalna, uznana zostanie
za błąd w czasie kompilacji.
I jeszcze jedno: lokalna klasa nie może mieć swoich składników statycznych.
Rozdz. 13 Zagnieżdżona definicja klasy 333
Lokalna definicja klasy
Pokażmy to wszystko na przykładzie
#include