联合(union)是一种特殊的类。
- 一个联合可以有多个数据成员,但在任意时刻只有一个数据成员有值。
- 当我们给union的某个成员赋值之后,该union的其他成员就变成未定义的状态了。
- 分配给一个union对象的存储空间至少要能容纳它的最大的数据成员
- union不能含有引用类型的成员,除此之外,它的成员可以是绝大多数类型。在C++11新标准中,含有构造函数或析构函数的类类型也可以作为union的成员类型。
- 当union包含的是内置类型的成员时,编译器将按照成员的次序依次合成默认构造函数或拷贝控制成员。但是如果union含有类类型的成员,并且该类型自定义了默认构造函数或拷贝控制成员,则编译器将为union合成对应的版本并将其声明为删除的。 例如,string类定义了五个拷贝控制成员以及一个默认构造函数。如果union含有string类型的成员,并且没有自定义默认构造函数或某个拷贝控制成员,则编译器将合成缺少的成员并声明成删除的(该union的默认构造函数和拷贝控制成员是删除的)。如果在某个类中含有一个union成员,而且该union含有删除的拷贝控制成员,则该类与之对应的拷贝控制操作也将是删除的。
对于union来说,要想构造或销毁类类型的成员必须执行非常复杂的操作,因此我们通常把含有类类型成员的union内嵌在另一个类当中。这个类可以管理并控制与union的类类型成员有关的状态转换。举例例子,我们为union添加一个string成员,并将我们的union定义成匿名union,最后将它作为Token类的一个成员。此时,Token类将可以管理union的成员。 为了追踪union中到底存储了什么类型的值,我们通常会定义一个独立的对象,该对象称为union的判别式(discriminant)。
#include<iostream>
#include<string>
using namespace std;
union ret
{
char buf[4];
int val;
};
class Token
{
public:
Token():tok(INT),ival(0){}
Token(const Token& t) :tok(t.tok)
{
copyUnion(t);
}
Token &operator=(const Token&);
~Token() {
if (tok == STR)
sval.~string();
}
Token& operator=(const string&);
Token& operator=(char);
Token& operator=(int);
Token& operator=(double);
private:
enum{ INT,CHAR,DBL,STR}tok;
union {
char cval;
int ival;
double dval;
string sval;
};
void copyUnion(const Token&);
};
Token& Token::operator=(int i)
{
if (tok == STR)
sval.~string();
ival = i;
tok = INT;
return *this;
}
Token& Token::operator=(char c)
{
if (tok == STR)
sval.~string();
cval = c;
tok = CHAR;
return *this;
}
Token& Token::operator=(double d)
{
if (tok == STR)
sval.~string();
dval = d;
tok = DBL;
return *this;
}
Token& Token::operator=(const string& s)
{
if (tok == STR)
sval = s;
else
new(&sval) string(s);
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;
//因为默认是直接初始化的ival ,所union中不存在string,因为直接placement new
case Token::STR: new (&sval) string(t.sval); break;
}
}
Token& Token::operator=(const Token& t)
{
if (tok == STR && t.tok != STR)
sval.~string();
if (tok == STR && t.tok == STR)
sval = t.sval;
else
copyUnion(t); //左侧没有string
tok = t.tok;
return *this;
}
参考文献:
C++ primer 第五版