YouTube视频链接
C++的联合体(union)
本文是ChernoP67视频的学习笔记。
联合体有点像类类型,或者结构体类型。只不过它一次只能占用一个成员的内存。若我们有一个结构体声明了4个浮点数,则有16个字节在这个结构体中。若用联合体声明声明4个浮点数,联合体的大小仍然是4个字节。我们可以给联合体添加静态函数或者普通函数或者方法等等,但不能使用虚方法。
通常使用联合体是和类型双关紧密相关的,当想给一个变量取两个不同的名字时非常有用。通常union是匿名使用的,但是匿名union不能含有成员函数。如下代码。
#include<iostream>int main()
{struct Union{union{float a;int b;};};Union u;u.a = 2.0f;std::cout << u.a << "," << u.b << std::endl;std::cin.get();
}
按F5运行代码得到2和107xxxx,因为107xxxx是浮点数形式的2字节表示,就好像取了组成浮点数的内存,然后把它解释成一个模型,这就是类型双关了。
如下代码有Vector2,Vector4结构体,还有一个函数PrintVector2,参数是vector,然后将其打印。
#include<iostream>struct Vector2
{float x, y;
};
struct Vector4
{float x, y, z, w;
};void PrintVector2(const Vector2& vector)
{std::cout << vector.x << "," << vector.y << std::endl;
}
int main()
{std::cin.get();
}
Vector4实际上是2个Vector2,所以构造一个Vector2,给它一些参数,返回整个对象,但是这会创建一个全新的对象,所以可以返回一个指向Vector2的引用,引用的x是一个类型双关的版本,我们要做的就是把x的内存地址转换成Vector2,然后解引用。
struct Vector4
{float x, y, z, w;Vector2& GetA(){return *(Vector2*)&x;}
};
另一种方法是使用union,这是一个匿名union,因为union只有一个成员,所以x,y,z,w会占用相同的空间,我们把它包装在一个匿名结构体中。现在这个结构体是union的一个成员,这是一个16字节的结构体。我们创建一个Vector4,可以正常访问vector.x并把它设为2.0f。
#include<iostream>struct Vector2
{float x, y;
};struct Vector4
{union{struct{float x, y, z, w;};};
};void PrintVector2(const Vector2& vector)
{std::cout << vector.x << "," << vector.y << std::endl;
}int main()
{Vector4 vector = { 1.0f,2.0f,3.0f,4.0f };vector.x = 2.0f;std::cin.get();
}
若给结构体取了名字A,则会报错。但如果它是匿名的,它只是一种数据结构,没有添加任何东西。这里的好处是它将所有变量转换成单个单元,这就是union所期望做的事。
若继续创建一个结构体,向union添加了第二个成员,它和第一个元素占据相同的空间,它有两个Vector2组成。
struct Vector2
{float x, y;
};struct Vector4
{union{struct {float x, y, z, w;};struct{Vector2 a, b;};};
};
现在有几种访问Vector4内数据的方法,可以用xywz或者ab,a和xy的内存是一样的,b和zw的内存一样。如下代码
int main()
{Vector4 vector = { 1.0f,2.0f,3.0f,4.0f };PrintVector2(vector.a);PrintVector2(vector.b);vector.z = 500.0f;std::cout << "------------------" << std::endl;PrintVector2(vector.a);PrintVector2(vector.b);vector.x = 2.0f;std::cin.get();
}
虽然没有碰过vector里b的部分,设置的是z=500,但它们占用了相同的内存。