C++中强制转为基类的指针是否一定指向派生类对象的内存区域?
问题解答
先给出两个核心结论:
- 你给出的示例代码整体属于未定义行为(UB),问题出在对象生命周期的合法性上。
- 抛开示例代码的UB问题,你关心的核心特性——合法派生类指针转公有基类指针时,所得基类指针必然落在派生类对象的内存区域内——是C++标准明确保障的,可以跨平台使用。
示例代码的UB问题
你代码中使用memcpy把d的字节复制到data数组后,data数组中并没有产生合法的derived对象:C++标准要求对象的生命周期必须由显式的构造调用来启动,单纯的字节拷贝不会启动对象生命周期。因此你后续reinterpret_cast<derived*>(data)得到的指针并不指向合法的derived对象,基于这个指针做基类转换的行为完全是未定义的,只是GCC、Clang的当前实现刚好给出了你预期的结果,不代表符合标准要求。
如果要修正这个UB,可以在memcpy之后用定位new显式启动对象生命周期:
// C++20及以上写法 std::construct_at(reinterpret_cast<derived*>(data), d); // 兼容旧标准的写法 new (data) derived(d);
修正后后续的指针转换就是合法行为。
派生类转基类指针的地址范围保障
对于生命周期合法的派生类对象,C++标准明确规定派生类对象包含所有基类子对象,基类子对象的存储是派生类对象存储的一部分,因此指向基类子对象的指针,其地址值必然满足:
(uintptr_t)derived_ptr <= (uintptr_t)base_ptr < (uintptr_t)derived_ptr + sizeof(derived)
这个保障和继承类型(单继承、多继承、虚继承)无关,也和平台指针位数(32位/64位)无关,所有符合C++标准的编译器都必须遵守,完全可以跨平台使用。
内容的提问来源于stack exchange,提问作者Object object
相关产品推荐
相关产品推荐

