将void指针强转为Derived类后调用重写方法触发段错误
问题原因分析
首先明确:你的代码本质是对未经过构造函数初始化的内存区域,强制类型转换为类对象指针后调用成员函数,这属于C++中的未定义行为,出现段错误是必然结果,非抽象基类的情况只是刚好没触发崩溃而已。
具体原因:
- 当类包含虚函数(抽象基类的纯虚函数属于虚函数),编译器会为该类生成虚函数表(vtable),每个对象的内存布局最开头会有一个虚表指针(vptr),指向对应的vtable。
- 你用
new char[500]分配的内存是未初始化的,直接转成Derived*后,对象的虚表指针是随机的垃圾值。 - 调用虚函数
base_method()时,程序需要通过虚表指针找到虚函数表,再定位到函数地址。由于虚表指针是无效值,访问这个地址就会触发段错误。
为什么非抽象具体基类可能没问题?
如果基类没有虚函数(非抽象但无虚函数),那么Derived也不会生成虚表,成员函数调用是静态绑定——编译器直接用函数的固定地址调用,不需要访问虚表。此时只要x的内存偏移正确(你的char数组足够大,刚好覆盖x的位置),就不会触发崩溃,但这依然是未定义行为,随时可能因为编译器优化、内存布局变化等出现问题。
正确的解决方法
要在已分配的内存上创建类对象,必须使用placement new来显式调用构造函数,初始化对象的虚表指针和成员变量:
#include <cstdio> #include <new> // 必须包含placement new的头文件 struct Base{ virtual void base_method() = 0; }; struct Derived : Base{ int x; void own_method(){ printf("own %d\n", x); } void base_method() override{ printf("base %d\n", x); } }; int main() { auto * char_ptr = new char[500]; // 使用placement new在char_ptr指向的内存上构造Derived对象 auto derived_ptr = new(char_ptr) Derived{}; derived_ptr->x = 15; derived_ptr->own_method(); derived_ptr->base_method(); // 现在可以正常调用,不会段错误 // 记得手动调用析构函数(因为placement new不会自动调用) derived_ptr->~Derived(); // 释放char数组的内存 delete[] char_ptr; return 0; }
注意事项:
- 使用placement new需要包含
<new>头文件。 - 用placement new构造的对象,必须手动调用析构函数,因为系统不会自动处理。
- 确保分配的内存大小足够容纳Derived对象(这里500字节足够,实际可以用
sizeof(Derived)来确认)。
内容的提问来源于stack exchange,提问作者Иван Поздняков
相关产品推荐
相关产品推荐

