Effective C++:unio

联合是一种特殊的类。一个union能够有多个数据成员,可是在任意时刻只有一个数据成员能够有值。当咱们给union中的某个成员赋值的以后,该union中的其余成员变成了未定义的状态。node

须要特别注意的是:ios

1,当给一个union类型分配空间的时候至少要分配能容纳它的最大的数据成员的空间。函数

2,C++11新标准中规定除了内置类型(int, double...),带有构造函数和析构函数的类型也能够做为union的成员类型。this

3,union也能够为其成员指定public, private, ptorected等权限标记符。可是默认状况下都是public的。spa

4,union不能够继承自其余class,也不能被其余class继承.code

5,union类型编译器是不会自动合成析构函数的咱们能够经过显式的写出来来保证非POD和内置类型的析构函数被调用.继承

 

使用union在编译时间作big-endian和little-endian的判断:内存

#include <iostream>
#include <vector>
#include <cstdint>

//static union { std::int32_t mylong; char c[4]; } endian_test = { 0x623f3f6c };

union endian_test { std::int32_t mylong; char c[4]; };
static constexpr endian_test test{ 0x623f3f6c };

inline static constexpr bool is_little_end(void) { return /*endian_*/test.c[0] == 'l'; }
inline static constexpr bool is_big_end(void) { return /*endian_*/test.c[0] == 'b'; }


int main()
{
	std::cout << std::boolalpha << is_little_end() << std::endl;
	std::cout << static_cast<char>(0x62)<< std::endl;
	return 0;
}

 

针对内置类型:编译器

#include <iostream>
#include <memory>
#include <string>

template<typename T>
class Node {
private:
	T data;

public:
	Node(const T& data_) :data(data_) {}
	~Node() = default;
	Node(const Node<T>& other) :data(other.data) {}
	Node<T>& operator=(const Node<T>& other) { this->data = other.data; return *this; };
	Node<T>& operator=(Node<T>&& other) { this->data = std::move(other.data); return *this; }
	Node(Node<T>&& other) :data(std::move(other.data)) {}

	template<typename Ty>
	friend std::ostream& operator<<(std::ostream& os, const Node<Ty>& node);
};

template<typename Ty>
std::ostream& operator<<(std::ostream& os, const Node<Ty>& node)
{
	os << node.data;
	return os;
}

class Tree {
private:
	int number;

public:
	Tree(const int& num) :number(num) {}
	Tree(const Tree& other) :number(other.number) {}
	Tree(Tree&& other) :number(std::move(other.number)) {}
	Tree& operator=(const Tree& other) { this->number = other.number; return *this; }
	Tree& operator=(Tree&& other) { this->number = std::move(other.number); return *this; }
	~Tree() = default;

	friend std::ostream& operator<<(std::ostream& os, const Tree& other);
};

std::ostream& operator<<(std::ostream& os, const Tree& other)
{
	os << other.number;
	return os;
}

//case 1:
union Token {
	int ival;
	double dval;
	char cval;
};

//case 2:
static union {
	char carVal;
	int iVal;
};

//case 3:
union InnerClass {
	Node<std::string> strNode; //error.

	Node<int> node;  //ok,模板类类型.
	Tree tree;
	char c;

	~InnerClass() { std::cout << "----------------" << std::endl; } //注意这里,咱们显式的写出了析构函数.
};

//case 4:
template<typename T>
union InnerTem {
	Node<T> node;
	Tree tree;
};

int main()
{
	//case 1:
	Token tk = { 't' };

	//case 2:
	iVal = 20;

	//case 3:
	InnerClass inCls = { "shihua" };

	//case 4:
	InnerTem<int> inTem = { 50 };

	//case 4.5:
	//InnerTem<std::string> inStr = { "shihua" }; //error错误.由于union没有析构函数.

	std::cout << tk.cval << std::endl;
	std::cout << iVal << std::endl;
	std::cout << inCls.strNode << std::endl;
	std::cout << inTem.node << std::endl;

	return 0;
}

针对类类型:string

#include <iostream>
#include <string>


class ManageTk{
	private:
		
		//匿名联合类型. 
		union{
			int iVal;  //int类型. 
			char cVal; //char类型.
			std::string sVal; //类类型std::string 
		};
		
		enum : int { CHAR, INT, STR } type; //type为匿名enum类型. 
		
		void copyUnion(const ManageTk& other);
		
		
		public:
			
		ManageTk():iVal(0), type(INT){}
		ManageTk(const int& val):iVal(val), type(INT){}
		ManageTk(const ManageTk& other);
		ManageTk(ManageTk&& other);
		
		ManageTk& operator=(const ManageTk& other);
		ManageTk& operator=(ManageTk&& other);
		
		ManageTk& operator=(const int& val);
		ManageTk& operator=(const char& val);
		ManageTk& operator=(const std::string& val);
		
		~ManageTk();
		
};

ManageTk::ManageTk(const ManageTk& other)
{
	if(this->type == STR && other.type != STR){  //若是当前union包含的是std::string,而other所包含的是其余类型 
	    using namespace std;
		sVal.~string();                         //那么先释放掉当前std::string的内存. 
		
	}
	
	if(this->type == STR && other.type == STR){  //若是当前union包含的是std::string,而other包含的是也是std::string 
		(this->sVal) = other.sVal;              //那么直接用other所包含的std::string赋值当前std::string. 
		
	}else{
		this->copyUnion(other);               //若是是其余的状况. 
	}
	
	this->type = other.type;
}

void ManageTk::copyUnion(const ManageTk& other)
{
	switch(other.type){
		case INT:
			{
				(this->iVal) = other.iVal;  //若是other说包含的是int类型. 
				break;
			}
			
		case CHAR:
			{
				(this->cVal) = other.cVal; //若是other所包含的是char类型. 
				break;
			}
			
		case STR:
			{
				new(&(this->sVal)) std::string(other.sVal); //若是other包含的是std::string类型,当前union包含的是其余类型. 
				break;                                   //这个时候当前union所包含的std::string还处于未定义状态. 
			}	                                         //最好仍是用new的定位形式赋值. 
	}
}

ManageTk::ManageTk(ManageTk&& other)
{
	if(this->type == STR && other.type != STR){
		using namespace std;
		(this->sVal).~string();
	}
	
	if(this->type == STR && other.type == STR){
		(this->sVal) = other.sVal;
		
	}else{
		this->copyUnion(other);
	}
	
	this->type = other.type;
}

ManageTk& ManageTk::operator=(const ManageTk& other)
{
	if(this->type == STR && other.type != STR){
		using namespace std;
		(this->sVal).~string();
	}
	
	if(this->type == STR && other.type == STR){
		(this->sVal) = other.sVal;
		
	}else{
		this->copyUnion(other);
	}
	
	this->type = other.type;
	return *this;
}

ManageTk& ManageTk::operator=(ManageTk&& other)
{
	if(this->type == STR && other.type != STR){
		using namespace std;
		(this->sVal).~string();
	}
	
	if(this->type == STR && other.type == STR){
		(this->sVal) = other.sVal;
		
	}else{
		this->copyUnion(other);
	}
	
	this->type = other.type;
	return *this;
}

ManageTk& ManageTk::operator=(const int& val)
{
	if(this->type == STR){
		using namespace std;
		(this->sVal).~string();
	}
	
	this->iVal = val;
	this->type = INT;
	
	return *this;
}

ManageTk& ManageTk::operator=(const char& val)
{
	if(this->type == STR){
		using namespace std;
		(this->sVal).~string();
	}
	
	this->iVal = val;
	this->type = CHAR;
	
	return *this;
}

ManageTk& ManageTk::operator=(const std::string& val)
{
	if(this->type == STR){
		this->sVal = val;
		
	}else{
		new(&(this->sVal)) std::string(val);
		
	}
	
	this->type = STR;
	return *this;
}


ManageTk::~ManageTk()
{
	if(this->type == STR){
		using namespace std;
		(this->sVal).~string();
	}
}

int main()
{
	ManageTk un;
	
	
	return 0;
}
相关文章
相关标签/搜索