什么是联合类型
在联合类型中多个对象可以共享一片内存,相应的这片内存也只能由一个对象使用。如下代码所示:
#include <iostream>
union U
{
int x1;
float x2;
};
int main()
{
U u;
u.x1 = 5;
std::cout << u.x1 << std::endl;
std::cout << u.x2 << std::endl;
u.x2 = 5.0;
std::cout << u.x1 << std::endl;
std::cout << u.x2 << std::endl;
}
在上面的代码中联合类型U里的成员变量x1和x2共享同一片内存,所以修改x1的值,x2的值也会发生相应的变化,反之亦然。
C++11 中的非受限联合类型
注意事项:在C++11中如果有联合类型中存在非平凡类型,那么这个联合类型的特殊成员函数将被隐式删除,也就是说
我们必须自己至少提供联合类型的构造和析构函数,例如:
#include <iostream>
#include <string>
#include <vector>
union U
{
U() {} // 存在非平凡类型成员,必须提供构造函数
~U() {} // 存在非平凡类型成员,必须提供析构函数
int x1;
float x2;
std::string x3;
std::vector<int> x4;
};
int main()
{
U u;
u.x3 = "hello world";
std::cout << u.x3;
}
注意:联合类型在析构的时候编译器并不知道当前激活的是哪个成员,所以无法自动调用成员的析构函数,必须由程序员编写代码完成这部分工作。所以可以看下面的代码。
推荐让联合类型的构造和析构函数为空,也就是什么也不做,并且将其成员的构造和析构函数放在需要使用联合类型的地方。修改上面的代码为:
#include <iostream>
#include <string>
#include <vector>
union U
{
U() {}
~U() {}
int x1;
float x2;
std::string x3;
std::vector<int> x4;
};
int main()
{
U u;
// placement new 技巧来初始化构造
new(&u.x3) std::string("hello world");
std::cout << u.x3 << std::endl;
u.x3.~basic_string();
new(&u.x4) std::vector<int>;
u.x4.push_back(58);
std::cout << u.x4[0] << std::endl;
u.x4.~vector();
}
placement new 在指定的内存地址上构造对象
Object * p = new (address) ClassConstruct(...);
注意
如果开发环境支持C++17标准,则大部分情况下我们可以使用 std:: variant 来代替联合体
具体variant的讲解见我以后的博客