union

联合(union)是一种特殊的类。

  • 一个联合可以有多个数据成员,但在任意时刻只有一个数据成员有值。
  • 当我们给union的某个成员赋值之后,该union的其他成员就变成未定义的状态了。
  • 分配给一个union对象的存储空间至少要能容纳它的最大的数据成员
  • union不能含有引用类型的成员,除此之外,它的成员可以是绝大多数类型。在C++11新标准中,含有构造函数或析构函数的类类型也可以作为union的成员类型。
  • 当union包含的是内置类型的成员时,编译器将按照成员的次序依次合成默认构造函数或拷贝控制成员。但是如果union含有类类型的成员,并且该类型自定义了默认构造函数或拷贝控制成员,则编译器将为union合成对应的版本并将其声明为删除的。 例如,string类定义了五个拷贝控制成员以及一个默认构造函数。如果union含有string类型的成员,并且没有自定义默认构造函数或某个拷贝控制成员,则编译器将合成缺少的成员并声明成删除的(该union的默认构造函数和拷贝控制成员是删除的)。如果在某个类中含有一个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 第五版



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值