На этом шаге мы покажем, как можно совместно использовать структуры и объединения.
Очень часто некоторые объекты программы относятся к одному и тому же классу, отличаясь лишь некоторыми деталями. Например, рассмотрим представление геометрических фигур. Общая информация об этих фигурах может включать такие элементы, как площадь и периметр. Однако соответствующая информация об их размерах может оказаться различной в зависимости от их формы.
В языках, таких как Ada и Pascal, имеется тип данных, называемый записью с вариантами, поля которой содержат набор одних и тех же компонент плюс компоненты, не являющиеся общими для всех остальных объектов. В языке C++ также имеется тип данных, подобный записи с вариантами, называемый переменной структурой (variant structure), которая может быть реализована с использованием комбинации структуры и объединения.
Рассмотрим для примера шаблон структуры figure:
struct figure { int area, perimeter; //Общие компоненты. int type; //Метка активной компоненты. union { int radius; // Окружность. int a[2]; // Прямоугольник. int b[3]; // Треугольник. } geom_fig; };
В общем случае каждый объект типа figure будет состоять из трех компонентов: area, perimeter и type. Компонент type называется меткой активного компонента (active component tag), так как он используется для указания, какой из компонентов объединения geom_fig (например, radius, a или b) является активным в данный момент. Такая структура называется переменной структурой, потому что ее компоненты меняются в зависимости от значения метки активного компонента.
В общем случае переменные структуры будут состоять из трех частей:
Общая форма переменной структуры имеет следующий вид:
struct { <общие компоненты> <метка активного компонента> union { <описание типа1> <компонента1> <описание типа2> <компонента2> . . . <описание типаN> <компонентаN> } <идентификатор> };
Проиллюстрируем сказанное на примере. Предположим, что даны следующие определения констант[1]:
#define CIRCLE 1 #define RECT 2 #define TRIANGLE 3
и что переменная fig определяется как: figure fig;. Тогда, по соглашению, перед присваиванием значения одному из компонентов соответствующее значение присваивается также переменной fig.type для указания активного компонента, например:
fig.type = CIRCLE; fig.geom_fig.radius = 5;.
Аналогично перед обращением к компоненту объединения необходимо проверить, является ли этот компонент активным, например:
switch (fig.type) { case CIRCLE: Обработать окружность; break; case RECT: Обработать прямоугольник; break; case TRIANGLE: Обработать треугольник; break; default: Ошибка; }
"Соберем" все сказанное в программу.
#include <iostream.h> #define CIRCLE 1 #define RECT 2 #define TRIANGLE 3 struct figure { int area, perimeter; //Общие компоненты. int type; // Метка активного компонента. union { int radius; // Окружность. int a[2]; //Прямоугольник. int b[3]; // Треугольник. } geom_fig; }; figure fig; void main () { cout << "Введите значение метки активного компонента... "; cin >> fig.type; switch (fig.type) { case CIRCLE: cout << "Введите радиус... "; cin >> fig.geom_fig.radius; cout << "Радиус: " << fig.geom_fig.radius; break; case RECT: cout << "Введите стороны прямоугольника... "; cin >> fig.geom_fig.a[0] >> fig.geom_fig.a[1]; fig.area = fig.geom_fig.a[0]*fig.geom_fig.a[1]; cout << "Площадь: " << fig.area; break; case TRIANGLE: cout << "Введите стороны треугольника... "; cin >> fig.geom_fig.b[0] >> fig.geom_fig.b[1] >> fig.geom_fig.b[2]; fig.perimeter=fig.geom_fig.b[0]+fig.geom_fig.b[1]+ fig.geom_fig.b[2]; cout << "Периметр: " << fig.perimeter; break; default: cout << "Ошибка!"; } }