Obiekty klasy można grupować w tablice. Zauważmy, że nie jest to możliwe w Javie, w której istnieją wyłącznie tablice typów prostych, w szczególności odnośników (wskaźników).
Nieco skomplikowana jest inicjalizacja takich takich tablic obiektów.
Jeśli klasa jest agregatem (patrz poprzedni podrozdział), to tworzona na stosie tablica obiektów tej klasy sama jest agregatem i może być inicjowana poprzez listę wartości w nawiasach klamrowych w odpowiedniej kolejności. Jeśli podamy za mało wartości, to reszta zostanie zainicjowana zerami (pustymi napisami, zerowymi wskaźnikami). Taką tablicę można też utworzyć nie podając w ogóle inicjatorów — w takim przypadku, tak jak to było dla tablic, wartości składowych będą miały wartość domyślną (która dla typów prostych wynosi „nieokreślona”).
W programie poniżej klasa
Klasa
jest agregatem, więc
tworzona w lini ➊ tablica też jest agregatem. Inicjujemy ją
przez podanie wartości składowych dla kolejnych obiektów, ale tylko
dla pierwszych czterech elementów; piąty będzie zatem wypełniony
zerami:
1. #include <iostream>
2. using namespace std;
3.
4. class Klasa {
5. public:
6. char imie[4];
7. int wiek;
8. };
9.
10. int main() {
11. Klasa ktab[5] = {{"Ala",17},{"Ola",32}, ➊
12. {"Ula",26},{"Iza",29}};
13. ktab[4].wiek = 22; ➋
14.
15. for (int i = 0; i < 5; i++)
16. cout << ktab[i].imie << " lat "
17. << ktab[i].wiek << endl;
18. }
W linii ➋ inicjujemy składową wiek dla ostatniego, piątego elementu. Składowa imie tego elementu pozostała wypełniona zerami; odpowiada to pustemu, tym niemniej dobrze zdefiniowanemu, C-napisowi:
Ala lat 17
Ola lat 32
Ula lat 26
Iza lat 29
lat 22
Zajmijmy się teraz przypadkiem, gdy klasa/struktura nie jest agregatem.
Tablicę obiektów takiej klasy można utorzyć bez jawnej inicjalizacji. Każdy element zostanie utworzony za pomocą konstruktora domyślnego. Zatem konstruktor domyślny musi dla takiej klasy istnieć!
Druga możliwość to na liście inicjalizacyjnej tablicy —
w nawiasach klamrowych — wywoływać jawnie konstruktory kreujące
obiekty anonimowe, jak w lini ➊ poniższego programu:
1. #include <iostream>
2. #include <string>
3. using namespace std;
4.
5. class Klasa {
6. string imie;
7. int wiek;
8. public:
9. Klasa(const string& imie = "No Name", int wiek = 100) {
10. this->imie = imie;
11. this->wiek = wiek;
12. cout << "konstrukcja " << this->imie << endl;
13. }
14.
15. int getAge() { return wiek; }
16.
17. string getImie() { return imie; }
18. };
19.
20. int main() {
21. Klasa ob("Celestyna");
22.
23. Klasa ktab[5] = { Klasa("Honoratka", 17), ➊
24. Klasa("Albertyna"),
25. Klasa("Hortensja", 26),
26. ob ➋
27. };
28.
29. for (int i = 0; i < 5; i++)
30. cout << ktab[i].getImie() << " lat "
31. << ktab[i].getAge() << endl;
32. }
Zauważmy, że tablica ma wymiar 5, ale jawnie skonstruowaliśmy tylko trzy jej elementy. Czwarty element będzie kopią wcześniej utworzonego obiektu ob (➋), a piąty będzie utworzony przez konstruktor domyślny. Musi on zatem w tej klasie istnieć — i istnieje, dzięki temu, że w jedynym konstruktorze zastosowaliśmy argumenty domyślne. Gdybyśmy jawnie zainicjowali wszystkie pięć elementów, to konstruktora domyślnego mogłoby nie być. Wydruk tego programu:
konstrukcja Celestyna
konstrukcja Honoratka
konstrukcja Albertyna
konstrukcja Hortensja
konstrukcja No Name
Honoratka lat 17
Albertyna lat 100
Hortensja lat 26
Celestyna lat 100
No Name lat 100
Zauważmy jeszcze konstrukcję z linii ➋: element czwarty tablicy ma
być tu kopią obiektu
ob. Aby to było możliwe,
musi istnieć publiczny konstruktor kopiujący; w naszej klasie
on istnieje, choć go nie widać — więcej o konstruktorach
kopiujących powiemy później.
Jeśli tablicę obiektów tworzymy na stercie (poprzez użycie operatora new), to nie ma możliwości indywidualnego inicjalizowania elementów tablicy: wszystkie zostaną utworzone za pomocą konstruktora domyślnego, który wobec tego musi istnieć.
T.R. Werner, 21 lutego 2016; 20:17