Объединения находятся в близком родстве со структурами. Объединением будем называть переменную, созданную, как и в случае структур, по шаблону. Определяютсяобъединения (шаблоныобъединения, объединяющие типы) с помощью служебного слова union. Объединения,подобно структурам, содержат поля различных типов, но только размещаются эти поля в одно и то же место памяти (начинаются с одной границы). Основное назначение объединения – обеспечить возможность доступа к одному и тому же участку памяти с помощью объектов разных типов.
Определим переменную UNI объединяющего типа с помощью анонимного шаблона:
union {
long L;
unsigned i1;
int i2;
char c[4];
} UNI;
Схема размещения переменной UNI в памяти:
long L
unsigned i1
int i2
char c[4]
т.е. элементы располагаются с одного адреса. Это подтвердит и выполнение следующих операторов:
cout << &UNI .L; //все переменные имеют один и тот же адрес
cout << &UNI. i1;
cout << &UNI. i2;
cout << &UNI .c;
Размер памяти, выделяемый объединению, равен максимальному из размеров памяти, выделяемых для отдельных полей шаблона. Тип поля может быть любым, в том числе и структурой. Структуры могут быть членами объединения, и объединение может быть членом структуры. Разрешается создание и массива объединений.
Переменные типа объединение могут быть формальными параметрами и аргументами вызова функций. Чтобы функция не изменила аргумент-объединение при передаче по указателю или ссылке, соответствующий параметр объявляется со спецификатором const. Функция может возвращать переменную-указатель или ссылку типа объединение.
Доступ к полям объединения выполняется, аналогично структурам, через уточненное имя:
имя_объединения. имя_поля
(*указатель_на_объединение). имя_поля
указатель_на_объединение -> имя_поля
ссылка_на_объединение. имя_поля
Внимание!!! Члены-данные анонимного объединения можно использовать как переменные (если их имена уникальны в контексте объявления). Например:
enum week {sun, mon, tues, weds, thurs, fri, sat};
union { // анонимное объединение
int i;
week w;
};
i = 6; if ((w == sun) || (w == sat)) cout << “Это выходные дни!”;
Объединения могут быть опасны, так как их реализация часто зависит от системы.
Если бы элементы объединения имели одинаковую длину и одинаковый тип, а отличались только именами, то использование объединения было бы подобно применению ссылок: один участок памяти имел бы несколько различных имен.
Заносить значения в участок памяти, выделенный для объединения, можно с помощью любого из элементов:
union {
int ival;
float fval;
char cval[4];
} uval;
Переменной uval можно присваивать любой из трех типов; какой тип в данный момент находится в переменной – должен помнить программист.
Но:
инициализироваться объединение может только первым описанным полем.
Инициализатор объединения – значение для его первого члена, заключенное в фигурные скобки. Например:
union int_flt {
int i;
float x;
} n = {0}; // член (поле) i инициализируется нулем.
n. i = 7; //в объединение записано целое значение
cout << n. i << endl; // объединение интерпретируется как имеющее целый тип
n. x = 7. 0; // в объединение записано вещественное значение
cout << n. x << endl; //объединение интерпретируется как имеющее вещественный тип
Основное достоинство объединений – возможность разных трактовок одного и того же содержимого памяти.
Пусть имеем объединение:
union
{float f;
unsigned long k;
} FK;
Можно присвоить объединению вещественное значение FK. f = -256.5, а рассматривать его затем как беззнаковое целое:
cout << hex << FK.k; //получим с3804000 16.
Если же включить в шаблон объединения массив:
union
{double f;
char h[8];
} FLH;
и выполнить присваивание вещественного значения переменной FLH присваиванием этого значения полю FLH .f, то имеем возможность доступа к отдельным байтам внутреннего представления этого значения с помощью имен FLH .h [0], FLH .h [1], и т.д.