//Token类型的对象只有一个成员,该成员的类型可能是下列类型中的任意一种
union Token {
char cval;
int ival;
double dval;
};
Token first_token = { 'a' }; //初始化cval成员Token last_token; //未初始化的Token对象Token *pt = new Token; //指向一个未初始化的Token对象的指针
Token last_token;
last_token.cval = 'z';
std::cout << last_token.cval << std::endl; //z
std::cout << last_token.ival << std::endl; //乱值
std::cout << last_token.dval << std::endl; //乱值
Token *pt = new Token;
pt->ival = 42;
std::cout << pt->cval << std::endl; //乱值
std::cout << pt->ival << std::endl; //42
std::cout << pt->dval << std::endl; //乱值
Token last_token;last_token.cval = 'c';printf("%c\t%c\t%c\n", last_token.cval, last_token.ival, last_token.dval);last_token.ival = 50;printf("%d\t%d\t%d\n", last_token.cval, last_token.ival, last_token.dval);
int main()
{
//匿名union,不能定义在全局作用域中
union {
char cval;
int ival;
double dval;
};
cval = 'c';
//此时union中的值都为cval指定的值
printf("%c\t%c\t%c\n", cval, ival, dval);
printf("%d\t%d\t%d\n", cval, ival, dval);
ival = 42;
//此时union中的值都为ival指定的值
printf("%c\t%c\t%c\n", cval, ival, dval);
printf("%d\t%d\t%d\n", cval, ival, dval);
return 0;
}
class Token
{
public:
//因为union含有一个string成员,所以Token必须定义拷贝控制成员
Token() :tok(INT), ival(0) {}
Token(const Token &t) :tok(t.tok) { copyUnion(t); }
Token &operator=(const Token&);
~Token() {
//如果union含有一个string成员,则我们必须销毁它
if (tok == STR)
sval.~string();
}
//下面的赋值运算符负责设置union的不同成员
Token &operator=(char);
Token &operator=(int);
Token &operator=(double);
Token &operator=(const std::string&);
private:
//判别式
enum { INT, CHAR, DBL, STR }tok;
//匿名union
union {
char cval;
int ival;
double dval;
std::string sval;
};
//检查判别式,然后酌情拷贝union成员
void copyUnion(const Token&);
};
Token &Token::operator=(char i)
{
//如果当前存储的string,需要释放
if (tok == STR)
sval.~string();
//进行一系列赋值
cval = i;
tok = CHAR;
return *this;
}
Token &Token::operator=(int i)
{
if (tok == STR)
sval.~string();
ival = i;
tok = INT;
return *this;
}
Token &Token::operator=(double i)
{
if (tok == STR)
sval.~string();
dval = i;
tok = DBL;
return *this;
}
Token &Token::operator=(const std::string& i)
{
//如果当前存储的就是string类型,那么直接赋值即可
if (tok == STR)
sval = i;
//如果不是,那么使用定位new,在sval的地址上创建一个string对象
else
new(&sval) string(i);
tok = STR;
return *this;
}
void Token::copyUnion(const Token& t)
{
switch (t.tok)
{
case Token::INT:
ival = t.ival;
break;
case Token::CHAR:
cval = t.cval;
break;
case Token::DBL:
dval = t.dval;
break;
case Token::STR:
new(&sval) string(t.sval);
break;
}
}
Token &Token::operator=(const Token& t)
{
//如果当前对象union存储的是string,那么需要先释放当前string
if ((tok == STR) && (t.tok != STR))
sval.~string();
//下面开始赋值操作
//如果当前对象union与要被拷贝的对象union中存储的都是string,那么直接赋值即可
if ((tok == STR) && (t.tok == STR))
sval = t.sval;
else //如果t.tok是STR,则需要构造一个string
copyUnion(t);
//判别式的设定
tok = t.tok;
return *this;
}