14.5.3. Записи с вариантами

Идея, которую мы обсудим в этом разделе, тоже в основном относится к повышению уровня удобств программирования. При реальном программировании достаточно часто возникает желание по-разному интерпретировать содержимое одной и той же области памяти в зависимости от конкретных обстоятельств. Хорошим стилем является использование каждой структурной переменной с некоторым объектом предметной области, к которой относится программа. Поля структуры в этом случае содержат требуемые характеристики объекта. Но любой объект может менять свое состояние и соответственно набор характеристик. Поэтому удобно, продолжая использовать ту же область памяти, иметь возможность понимать ее структуру и содержание таким образом, который согласуется с текущим состоянием объекта.

Наиболее строгое решение содержится в языках линии Паскаль. В определении всего структурного типа или его завершающей части можно явно указать специальное поле перечисляемого типа (дискриминант), значения которого являются метками соответствующих вариантов типа записи. Для корректного использования переменных такого типа требуется заносить в поле дискриминанта актуальное значение при изменении интерпретации переменной и руководствоваться значением дискриминанта при доступе к содержимому переменной. Вот пример определения типа записи с вариантами в языке Паскаль:

Пример 14.4. Определения типа записи с вариантами в языке Паскаль

type person = record  lname, fname: alfa;
       birthday: date;
       marstatus: (single, married);
       case sex: (male, female) of
          male: (weight: real;
          bearded: boolean);
       female: (size: array[1..3] of integer)
    end

(Считается, что типы данных alfa и date уже определены.) После определения переменной типа person в любой момент можно обращаться и к полям weight и bearded, и к элементам массива size, но корректно это следует делать, руководствуясь значением дискриминанта sex.

Более слабый, но эквивалентный по возможностям механизм поддерживается в языках семейства Си. В этих языках существует специальная разновидность типов данных, называемая смесью (union). Фактически, смесь – это запись с вариантами, но без явно поддерживаемого дискриминанта. По нашему мнению, решение о применении такого "облегченного" механизма было принято потому, что использование явно задаваемого дискриминанта в языках линии Паскаль все равно является необязательным, а раз так, то при желании можно просто включить дополнительное поле, значение которого будет характеризовать применимый вариант. Приведенный выше пример можно было бы переписать на языке Си следующим образом:

Пример 14.5. Определения типа записи с вариантами в языке Си

struct person  { char lname[10], fname[10];
      integer birthday;
      enum { single, married } marstatus;
      enum { male, female } sex;
      union {
      struct { float weight;
       integer bearded } male;
      integer female[3];
        } pers;
     }