void*指针类型转换笔记
void*指针类型转换笔记
#include <iostream>// 基类1
class Base1 {
public:int x;Base1() : x(100) {}
};// 基类2
class Base2 {
public:int y;Base2() : y(200) {}
};// 派生类(你要求叫 Sub)
class Sub : public Base1, public Base2 {
public:int z;Sub() : z(300) {}
};int main() {// 1. 创建 Sub 对象Sub obj;Sub* src = &obj;// 2. 转成 void*void* p = src;// 3. 从 void* 转回 Base2*Base1* base1 = (Base1*)p; // base1 多重继承的第一个基类,没有偏移量,虽然正确,但是显示中也是存在风险的,不建议这么用Base2* base2 = (Base2*)p; // base2 多重继承的第二个基类,偏移量错了,将base1的空间赋给Base2指针了,本例中不会有问题,因为一开始也是个int内存空间,但现实中会调至不可预测的结果Base2* base3 = (Base2*)src; // 有类型的src指针转基类指针,会自动找到正确的Base2偏移量,使基类指针可以正确使用。// 使用static_cast转部分编译会报错// Base1* base1 = static_cast<Base1*>(p); // base1 多重继承的第一个基类,没有偏移量,虽然正确,但是显示中也是存在风险的,不建议这么用// Base2* base2 = static_cast<Base2*>(p); // base2 多重继承的第二个基类,偏移量错了,将base1的空间赋给Base2指针了,本例中不会有问题,因为一开始也是个int内存空间,但现实中会调至不可预测的结果// Base2* base3 = static_cast<Base2*>(src); // 有类型的src指针转基类指针,会自动找到正确的Base2偏移量,使基类指针可以正确使用。Sub* dst = static_cast<Sub*>(p);// 4. 验证:是否能正确访问 y?std::cout << "obj address: " << src << std::endl;std::cout << "sub address: " << dst << std::endl;std::cout << "base1 address: " << base1 << std::endl;std::cout << "base2 address: " << base2 << std::endl;std::cout << "base3 address: " << base3 << std::endl; // 可以虽然将src赋值给base3,但是两个指针的地址并不相同,是因为转父类指针时,自动填上将了便宜量,本例子中是4个字节。// 5. 输出变量std::cout << "src[x:" << src->x << ", y:" << src->y << ", z:" << src->z << "]" << std::endl;std::cout << "dst[x:" << dst->x << ", y:" << dst->y << ", z:" << dst->z << "]" << std::endl;std::cout << "base1[x:" << base1->x << "]" << std::endl; // base1没有偏移量,虽然正确,但是存在风险,不建议用std::cout << "base2[y:" << base2->y << "]" << std::endl; // 此处可以看到,base2的值其实是base1的内存空间,存的是值是100std::cout << "base3[y:" << base3->y << "]" << std::endl; // 带类型的转换,数据正确, 所以我们的指针如果转成void*,如果想用,我们需要将其转成其真实的类型指针再使用. 如果真的需要基类指针,转成原始类型指针后再转基类指针,就可以诡辩风险。return 0;
}
总结:
类对象指针转成 void* 后,若要还原,必须先转回原始类指针,再通过 static_cast 转为基类指针。
禁止直接将 void* 强转为非首基类指针,否则指针偏移错误,访问将导致未定义行为。