С++ для начинающих




Объединение – класс, экономящий память - часть 3


union TokenValue {

public:

   TokenValue(int ix) : _ival(ix) { }

   TokenValue(char ch) : _cval(ch) { }

   // ...

   int ival() { return _ival; }

   char cval() { return _cval; }

private:

   int _ival;

   char _cval;

   // ...

};

int main() {

   TokenValue tp(10);

   int ix = tp.ival();

   //...

}

Вот пример работы объединения TokenValue:

enum TokenKind ( ID, Constant /* и другие типы лексем */ }

class Token {

public:

   TokenKind tok;

   TokenValue val;

};

Объект типа Token можно использовать так:

int lex() {

   Token curToken;

   char *curString;

   int curIval;

   // ...

   case ID:  // идентификатор

      curToken.tok = ID;

      curToken.val._sval = curString;

      break;

   case Constant:   // целая константа

      curToken.tok = Constant;

      curToken.val._ival = curIval;

      break;

   // ... и т.д.

}

Опасность, связанная с применением объединения, заключается в том, что можно случайно извлечь хранящееся в нем значение, пользуясь не тем членом. Например, если в последний раз значение присваивалось _ival, то вряд ли понадобится значение, оказавшееся в _sval. Это, по всей вероятности, приведет к ошибке в программе.

Чтобы защититься от подобного рода ошибок, следует создать дополнительный объект, дискриминант объединения, определяющий тип значения, которое в данный момент хранится в объединении. В классе Token роль такого объекта играет член tok:

char *idVal;

// проверить значение дискриминанта перед тем, как обращаться к sval

if ( curToken.tok == ID )

   idVal = curToken.val._sval;

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

#include <cassert>

// функции доступа к члену объединения sval

string Token::sval() {

   assert( tok==ID );

   return val._sval;

}

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




Содержание  Назад  Вперед