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;
}
相關文章
相關標籤/搜索