C++中通过错误指针调用基类成员函数的合法性及虚拟场景影响
C++代码合法性分析(仅语言规则层面)
原代码
struct Base { int f() { return 42; } }; struct D1 : Base {}; struct D2 : Base {}; int main() { D2 d2; D1* ouch = reinterpret_cast<D1*>(&d2); return ouch->f(); }
原代码合法性判断
这段代码是合法的。核心依据如下:
- 非虚成员函数
Base::f()的调用地址在编译阶段就已确定,不依赖运行时对象的实际类型。 ouch->f()本质是将D1*类型的ouch隐式转换为Base*,作为this指针传递给Base::f()。D1和D2都是Base的非虚单继承派生类,其内存布局中Base子对象位于派生类对象起始位置。reinterpret_cast得到的ouch指向D2对象的起始地址,转换为Base*后恰好指向D2中有效的Base子对象,满足非静态成员函数对this指针的有效性要求。
变体情况分析
1. 当f()为虚函数时
此时代码属于未定义行为。
虚函数调用依赖对象的虚表指针:D2对象的虚表指针指向D2的类虚表,而通过reinterpret_cast得到的D1*指针调用虚函数时,编译器会按照D1的内存布局访问虚表。C++标准未保证不同派生类的虚表布局或虚表指针位置一致,这种跨类型的虚函数调用违反类型安全,行为完全不可预期。
2. 当继承为虚继承时
无论f()是否为虚函数,代码均属于未定义行为。
虚继承下,Base子对象在派生类中的位置由编译器自由决定,不再固定在起始位置。D1和D2的Base子对象位置可能不同,reinterpret_cast<D1*>(&d2)转换后的指针,在隐式转为Base*时无法正确指向D2中的Base子对象,导致this指针无效,触发未定义行为。
内容的提问来源于stack exchange,提问作者dtldarek
相关产品推荐
相关产品推荐

