根据严格的别名规则:
struct B { virtual ~B() {} };
struct D : public B { };
D d;
char *c = reinterpret_cast<char*>(&d);
Achar*
对任何不同类型的对象都是有效的。但现在的问题是,它会指向 &d 的同一个地址吗?C++ 标准对返回相同地址的保证是什么?
根据严格的别名规则:
struct B { virtual ~B() {} };
struct D : public B { };
D d;
char *c = reinterpret_cast<char*>(&d);
Achar*
对任何不同类型的对象都是有效的。但现在的问题是,它会指向 &d 的同一个地址吗?C++ 标准对返回相同地址的保证是什么?
c
并且&d
确实具有相同的值,并且如果您重新解释c
转换回 aD*
您将获得一个可以取消引用的有效指针。此外,您可以将c
其视为(指向第一个元素的)不透明数组char[sizeof(D)]
——这确实是将指针转换为 char 指针的主要目的:允许(反)序列化(例如ofile.write(c, sizeof(D));
),尽管您通常应该只为原始类型(及其数组),因为复合类型的二进制布局通常不以可移植方式指定。
正如@Oli 正确指出并希望我强调的那样,您真的不应该将复合类型作为一个整体进行序列化。结果几乎永远不会反序列化,因为未指定多态类的实现和数据字段之间的填充,并且您无法访问。
请注意,可以通过类似的推理reinterpret_cast<char*>(static_cast<B*>(&d))
将其视为不透明数组。char[sizeof(B)]
2003 C++ 标准的第 5.2.10 节第 7 点说:
指向对象的指针可以显式转换为指向不同类型对象的指针。除了将“指向 T1 的指针”类型的右值转换为“指向 T2 的指针”类型(其中 T1 和 T2 是对象类型,并且 T2 的对齐要求不比 T1 的对齐要求更严格)并返回其原始类型会产生原始指针值,这种指针转换的结果是未指定的。
如果“相同地址”是指“原始指针值”,则该条目表示“是”。
意图很明确(不需要辩论):
reinterpret_cast
永远不会更改地址的值,除非目标类型不能表示所有地址值(如小整数类型,在具有内在对齐的指针类型上:f.ex. 只能表示偶数地址的指针,或指向对象的指针和指向函数的指针不能混合......)。
该标准的措辞未能体现这一点,但这并不意味着这里存在真正的实际问题。
char *c = reinterpret_cast<char*>(&d);
c
将始终指向 的第一个字节d
。