联合是一种特殊的类。一个union可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当我们给union中的某个成员赋值的之后,该union中的其他成员变成了未定义的状态。
需要特别注意的是:
1,当给一个union类型分配空间的时候至少要分配能容纳它的最大的数据成员的空间。
2,C++11新标准中规定除了内置类型(int, double...),带有构造函数和析构函数的类型也可以作为union的成员类型。
3,union也可以为其成员指定public, private, ptorected等权限标记符。但是默认情况下都是public的。
4,union不可以继承自其他class,也不能被其他class继承.
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;
}
针对类类型:
#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;
}
来源:oschina
链接:https://my.oschina.net/u/2516597/blog/708956