6.2 Specyfikator typedef

Skomplikowanym typom, które omawialiśmy w poprzednim podrozdziale, można nadawać nazwy („aliasy”) za pomocą deklaracji typedef. Procedura jest przy tym następująca:

Pamiętajmy, że w ten sposób określamy nazwę (alias) istniejącego, być może skomplikowanego, typu, a nie tworzymy nowego typu. Do tworzenia nowych typów służą w C++ inne konstrukcje: klasy i struktury.

Na przykład po deklaracji

       long MY_INT;
zmienna MY_INT byłaby typu long. Zatem po
       typedef long MY_INT;
MY_INT jest inną nazwą typu long. Deklaracja
       MY_INT k;
jest zatem od tej pory (w zakresie, w którym widoczna jest deklaracja typedef) równoważna deklaracji
       long k;
Zwykle jednak wprowadzamy nazwy dla bardziej skomplikowanych typów, często zagnieżdżając deklaracje typedef, co jest dozwolone. Jako przykład rozpatrzmy program, w którym:

P29: typedef.cpp     Deklaracja typedef

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  int main() {
      5.      typedef char CH1[3];
      6.      typedef CH1  CH2[2];
      7.      typedef CH2  CH3[2];
      8.  
      9.      CH1 ch1 = {'a','b','c'};
     10.  
     11.      CH2 ch2 = {{'a','b','c'},{'d','e','f'}};
     12.  
     13.      CH3 ch3 = {
     14.                    {{'a','b','c'},{'d','e','f'}},
     15.                    {{'g','h','i'},{'j','k','l'}},
     16.                };
     17.  
     18.      cout << "sizeof(CH1)  = " << sizeof(CH1)  << endl
     19.           << "sizeof(CH2)  = " << sizeof(CH2)  << endl
     20.           << "sizeof(CH3)  = " << sizeof(CH3)  << endl
     21.           << "ch1[2]       = " << ch1[2]       << endl
     22.           << "ch2[1][1]    = " << ch2[1][1]    << endl
     23.           << "ch3[1][0][2] = " << ch3[1][0][2] << endl;
     24.  }

W tym przypadku typ CH3 jest koncepcyjnie równoważny trzywymiarowej tablicy znaków o wymiarach 2×2×3. Wynik tego programu

    sizeof(CH1)  = 3
    sizeof(CH2)  = 6
    sizeof(CH3)  = 12
    ch1[2]       = c
    ch2[1][1]    = e
    ch3[1][0][2] = i
a w szczególności wypisane dla poszczególnych typów rozmiary, świadczą o poprawnym zinterpretowaniu zadeklarowanych typów.

Najczęściej używa się specyfikatora typedef, aby wygodniej określać typ parametrów lub typ zwracany funkcji, szczególnie, jeśli pojawia się w wielu miejscach programu. Rozpatrzmy na przykład program:


P30: typedef1.cpp     Deklaracje typedef i funkcje

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  typedef int IN3[][2][2];
      5.  
      6.  int fun(IN3 t) {
      7.      int max = t[0][0][0];
      8.      for (int k = 0; k < 2; ++k)
      9.          for (int j = 0; j < 2; ++j)
     10.              for (int i = 0; i < 2; ++i)
     11.                  if (t[k][j][i] > max)
     12.                      max = t[k][j][i];
     13.      return max;
     14.  }
     15.  
     16.  int main()
     17.  {
     18.      IN3 in3 = { {{4,3},{2,1}},
     19.                  {{7,8},{5,6}} };
     20.  
     21.      int max = fun(in3);
     22.  
     23.      cout << "max = " << max << endl;
     24.  }

W przykładzie powyżej typ IN3 jest nazwą typu trzywymiarowa tablica liczb o drugim i trzecim wymiarze równym 2. Dzięki zadeklarowaniu nazwy IN3 definicja funkcji i deklaracja zmiennej in3 w programie są prostsze i czytelniejsze. Funkcja fun znajduje i zwraca wartość największego elementu argumentu, będącego trzywymiarową tablicą liczb — wynikiem jest oczywiście ' max=8'.

T.R. Werner, 25 lutego 2017; 22:31