×
Traktatov.net » Язык программирования C++. Пятое издание » Читать онлайн
Страница 688 из 714 Настройки

Если у объединения есть члены только встроенного типа, компилятор сам синтезирует почленные версии стандартного конструктора и функций-членов управления копированием. Но для объединений, у которых есть член типа класса, определяющего собственный стандартный конструктор или функция-член управления копированием, это не так. Если тип члена объединения определяет одну из этих функций-членов, компилятор синтезирует соответствующий член объединения как удаленный (см. раздел 13.1.6).

Например, класс >string определяет все пять функций-членов управления копированием, а также стандартный конструктор. Если объединение будет содержать строку и не определит ее собственный стандартный конструктор или одну из функций-членов управления копированием, то компилятор синтезирует эту недостающую функцию как удаленную. Если у класса будет член типа объединения, у которого есть удаленная функция-член управления копированием, то соответствующая функция (функции) управления копированием самого класса также будет удалена.

Использование класса для управления членами объединения

Из-за сложностей создания и удаления членов типа класса такие объединения обычно встраивают в другой классе. Таким образом, класс получает возможность управлять состоянием при передаче из и в элемент типа класса. В качестве примера добавим в объединение член класса >string. Определим объединение как анонимное и сделаем его членом класса >Token. Класс >Token будет управлять членами объединения.

Для отслеживания вида значения хранимого объединением обычно определяют отдельный объект, дискриминант (discriminant). Дискриминант позволяет различать значения, которые может содержать объединение. Для синхронизации объединения и его дискриминанта сделаем дискриминант также членом класса >Token. Для отслеживания состояния члена объединения класс определит член типа перечисления (см. раздел 19.3).

Единственными определяемыми классом функциями будут стандартный конструктор, функции-члены управления копированием и ряд операторов присвоения, способных присваивать значение одного из типов объединения члену другого:

>class Token {

>public:

> // функции управления копированием необходимы потому, что у класса

> // есть объединение с членом типа string

> // определение конструктора перемещения и оператора присваивания при

> // перемещении остается в качестве самостоятельного упражнения

> Token(): tok(INT), ival{0} { }

> Token(const Token &t): tok(t.tok) { copyUnion(t); }

> Token &operator=(const Token&);

> // если объединение содержит строку, ее придется удалять;

> // см. раздел 19.1.2

> ~Token() { if (tok == STR) sval.~string(); }

> // операторы присвоения для установки разных членов объединения

> Token &operator=(const std::string&);

> Token &operator=(char);

> Token &operator=(int);

> Token &operator=(double);

>private:

> enum {INT, CHAR, DBL, STR} tok; // дискриминант

> union { // анонимное объединение

>  char cval;

>  int ival;

>  double dval;

>  std::string sval;

> }; // у каждого объекта класса Token есть безымянный член типа этого

>    // безымянного объединения

> // проверить дискриминант и скопировать член объединения, как надо