C++ has some good compatability with the C language, which offers good support for low-level machine level programming construct, the union and the bitfield are two examples of such...
Union
the union is a special kind of class, the data members inside the union are stored in memory in such a way that they overlap with each other.
that's said, it means the union should have the following.
what a union can have
- it can contain public/private access modifier
- it can contains constructor or destructor
- it can conly copy assignment operator or something...
while what union cannot have:
- it cannot have member who has contructor, destructor, or copy assignment operator
- it cannot have static member functions
- It cannot have reference members such as int &rfi;
First, let's suppose that we have a lex parser, which can pase
int i = 0;
to a sequence of symbols
Type, ID, Assign, Constant, Semicolon;
so, we can define a enum to represent each type of the symbols.
enum TokenKind
{
Type,
ID,
Assign,
Constant,
Semicolon
};
and we have to define a union that can reprent the values of the datas of the symbols.
union TokenValue {
public :
TokenValue() {}
TokenValue(int ix_ ): _ival(ix_) {}
TokenValue(char ch_) : _cval(ch_) {}
TokenValue(char * sval_): _sval(sval_) {}
TokenValue(double dval_) : _dval(dval_) {}
int ival() { return _ival; }
char cval() { return _cval; }
char * sval() { return _sval;}
double dval() { return _dval;}
char _cval;
int _ival;
char *_sval;
double _dval;
};
class Token
{
public:
TokenKind tok;
TokenValue val;
};
As you can see, the union type TokenValue has access modifier, it has the member functions, and it has constructors.
To use the union, we can define a class which has both the union as the value and a enum as the indicator which tracks the type of value stored inside the union.
here is one simple code .
TokenKind parse()
{
return ID;
}
/*
* below shows you how to use the union, it is a best practise to keep a token kind to keep track of what type of data is stored in the union type.
*/
int lex() {
Token curToken;
char * curString;
int curIVal;
switch (parse()) {
case ID:
curToken.tok = ID;
curToken.val._sval = curString;
break;
case Constant:
curToken.tok = Constant;
curToken.val._ival = curIVal;
break;
default:
break;
}
return 0;
}
Bit fields
A specied class data member , referenced to as bit-fields, can be declared to hold a specified number of bits. A bit fields must have an integral data type, It can either signed or unsigned.
/**
*bit fiels
* bit fiels is a space saving member
*/
typedef unsigned int Bit;
class File {
public:
Bit mode: 2;
Bit modified : 1;
Bit prot_owner : 3;
Bit prot_group : 3;
Bit prot_world : 3;
void write();
void close();
};
void File:: write() {
modified = 1;
}
void File::close() {
if (modified) {
// ... save contents
}
}
enum { READ = 01, WRITE = 02 } ;
int test_bitfields() {
File myfile ;
myfile.mode != READ;
if (myfile.mode & READ) {
cout << "myfile.mode is set to READ \n";
}
}