14.9 Tablice obiektów

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:


P110: agrtab.cpp     Tablice klas-agregatów

      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:


P111: classtab.cpp     Tablice obiektów

      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