类型双关
c++作为一个强类型语言,它拥有一个类型系统 ,当我们在创建变量时必须声明整数,双精度,单精度,布尔类型或者结构体等,并且这种类型系统并不强制进行,在c++中即使类型时编译器强行执行的,但是我们可以直接访问内存。即,当我们想将一段整形类型内存当作double使用时我们可以直接访问它的内存,可以轻易饶过类型系统,如果有一个类或者结构,没有指向别处的指针,那么我们可以重新对解释整个结构或者类。在应用时,比如将一个类型变成一个字节数组写出来等。但是除非需要,否则不要轻易使用,这也是c++的效率很高的原因。
代码解释如下:
1 2 3 4 5 6 7 8
| #include <iostream>
int main() { int a = 50; double value = a; std::cout << value << std::endl; }
|
以上例子中我们在第7行加上断点,取a地址内存时如下

而我们的value的地址如下:

由此我们发现此处49和40对应不上我们的数值,这是因为在程序中进行了隐式转换,实际上他不知道要转换成什么。但是还是照旧转换。
那么我们如果想将int对应的地址直接当作double来看呢?我们使用一个较为原始的方法来,如下:
1 2 3 4 5 6 7 8
| #include <iostream>
int main() { int a = 50; double value = *(double*) &a; std::cout << value << std::endl; }
|
此处运行结果为:

此处我们再来看value的地址如下:

此处我们发现double是8位,这里则有后四位均是未初始化内存。这个过程是在我们int内存之后继续增加了4个字节的位置,然后复制过来在一个新空间使用,但是虽然可以写入,但是在读取时我们依旧读取了int后那不属于自己的四位内存,这很不好。甚至当我们不想复制直接将int当double时我们可以使用引用 即
1
| double& value = *(double*) &a;
|
此处是非常危险的,因为这样在修改时,我们会修改int后新增的4位,会导致修改不属于我们的内存。
下面使用一个更具象的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream>
struct Entity { int x, y; };
int main() { Entity e = { 5,8 };
std::cin.get(); }
|
以上代码中我们寻址e的地址发现:

里面存储了5,8在结构体中,如果没有任何成员等,它至少会有一个字节的大小,因为需要寻址,如果有成员变量,那么他们是相互挨在一起的。并且只有这成员变量的大小,类似数组。我们可以直接访问内存的方式得到这些值。
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream>
struct Entity { int x, y; int* GetPositions() { return &x; } };
int main() { Entity e = { 5,8 };
int* position = (int*)&e; std::cout << position[0] << "," << position[1] << std::endl;
std::cin.get(); }
|
如上代码我们直接通过访问内存来访问数值输出结果为:

联合体
联合体(union)有点类似于类,但是它一次只能占用一 个成员内存,比如当我声明4个浮点数时在类中会占用4*4个字节,在union中则为4个字节。但是由于四个公用相同的内存,则改变其中一个值则其他的会跟着改变。他没有虚函数。一般和类型双关使用居多。
使用示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #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(); }
|
输出结果如下:

此处a,b公用内存,即b的值为用a的内存存储的数值用int类型解释所得。即同一内存地址被不同类型解释
下面进行一个更加直观的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include <iostream>
struct Vector2 { float x,y; };
struct Vector4 { union { struct { float x,y,z,w; }; struct { Vector2 a,b; }; }; };
void PrintVector(const Vector2& vector) { std::cout << vector.x << "," << vector.y << std::endl; }
int main() { Vector4 vector = {1.0f, 2.0f, 3.0f,4.0f}; PrintVector(Vector.a); PrintVector(Vector.b); vector.z =500.0f std::cout << std::endl; PrintVector(Vector.a); PrintVector(Vector.b); std::cin.get(); }
|
运行结果如下:

此处可以发现,a对应x则b是对应z的位置,所以a占据x地址,b占据z地址。
资料参考:
youtube上the cherno的cpp系列