C++多态疑问:强制类型转换后调用虚函数为何触发非目标函数?
为什么强制转换无关类指针后调用虚函数会出现奇怪行为?
这是个非常典型的C++底层内存布局和未定义行为问题,咱们一步步把它说清楚:
首先明确:你的代码属于未定义行为
Class1和Class2是完全独立的两个类,没有任何继承关系,你用(Class1*)&object2这种C风格强制转换,本质上是在欺骗编译器——告诉它“这个Class2对象的地址就是Class1对象的地址”,但从C++类型系统的角度来说,这完全是非法的。
未定义行为的意思是:C++标准对这种情况的结果没有任何规定,程序可能崩溃、可能调用奇怪的函数、甚至可能看起来“正常运行”,一切都是不可预测的。你看到调用了h()只是巧合下的一种表现而已。
为什么会调用h()?——虚函数表的底层逻辑
几乎所有主流编译器(GCC、Clang、MSVC)对带虚函数的类,内存布局都是这样的:
- 对象的第一个成员是虚函数表指针(vptr),它指向该类的虚函数表(vtable);
- 虚函数表是一个函数指针数组,里面按类声明的顺序存放着所有虚函数的地址。
具体到你的代码:
- Class1的虚表里只有一个条目:
f()的地址(是第1个位置); - Class2的虚表里也只有一个条目:
h()的地址(同样是第1个位置)。
当你把Class2对象的地址强制转换成Class1*后,指针p“误以为”自己指向的是Class1对象,于是它会:
- 读取对象的第一个指针(也就是Class2的vptr);
- 去这个vptr指向的虚表里,取第1个位置的函数指针;
- 调用这个函数——而这个位置正好是Class2的
h(),所以就出现了调用h()的情况。
为什么可能触发程序异常终止?
这次只是刚好两个类的虚表都只有一个函数,位置对应上了。如果换一种情况:
- 比如Class1有两个虚函数
f()、g(),Class2只有一个h(); - 或者编译器对某个类的内存布局做了特殊优化;
- 或者类里还有其他非虚成员变量。
那当你用错误的指针去调用函数时,就可能读取到虚表里的无效地址,或者访问到不属于当前对象的内存,直接触发段错误、程序崩溃等异常。
关于多态的补充
你开头问“C++中多态是否可通过同名函数调用不同虚函数”——合法的多态必须基于继承关系:比如让Class2继承自Class1,并重写f(),然后用Class1*指针指向Class2对象,调用f()才是正确的多态用法,这时候编译器会正确地调用派生类的f(),完全不存在未定义行为。
内容的提问来源于stack exchange,提问作者John Young
相关产品推荐
相关产品推荐

