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 100Zauważ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