c++ - 为什么 MSVC 和 GCC 在 vtable 中以不同方式放置覆盖的纯虚函数?
问题描述
首先,MCVE:
#include <cstdio>
class Base {
public:
virtual void Print(int x) = 0;
virtual void Print(double x) = 0;
};
class Derived : public Base {
public:
void Print(int x) override { printf("%d\n", x); }
void Print(double x) override { printf("%lf\n", x); }
};
int main(void) {
class Derived obj;
obj.Print(2);
obj.Print(3.141);
}
在上面的 C++ 代码中,基类有两个函数名称相同但参数类型不同的纯虚函数——第一个打印整数,第二 个打印双精度数。具有相同的虚拟方法名称很重要,因为如果方法名称相同,则 MSVC 和 GCC 在结果二进制文件中产生相同的效果。
在反汇编(IDA):
- GCC 10.2.0:
g++.exe -Wall -pedantic test.cpp
.rdata:A0 ; `typeinfo name for'Base
.rdata:A0 _ZTS4Base db '4Base',0 ; type descriptor name
.rdata:A6 align 10h
.rdata:B0 public _ZTS7Derived
.rdata:B0 ; `typeinfo name for'Derived
.rdata:B0 _ZTS7Derived db '7Derived',0 ; type descriptor name
.rdata:B9 align 20h
.rdata:C0 public _ZTV7Derived
.rdata:C0 ; `vtable for'Derived
.rdata:C0 _ZTV7Derived dq 0 ; offset to this
.rdata:C8 dq offset _ZTI7Derived ; `typeinfo for'Derived
.rdata:D0 off_4098D0 dq offset _ZN7Derived5PrintEi ; Derived::Print(int)
.rdata:D8 dq offset _ZN7Derived5PrintEd ; Derived::Print(double)
- MSVC 19.26.28806:
cl.exe /Zi test.cpp
.rdata:20 dq offset ??_R4Base@@6B@ ; const Base::`RTTI Complete Object Locator'
.rdata:28 ??_7Base@@6B@ dq offset j__purecall
.rdata:30 dq offset j__purecall
.rdata:38 align 20h
.rdata:40 dq offset ??_R4Derived@@6B@ ; const Derived::`RTTI Complete Object Locator'
.rdata:48 ??_7Derived@@6B@ dq offset j_?Print@Derived@@UEAAXN@Z ; Derived::Print(double)
.rdata:50 dq offset j_?Print@Derived@@UEAAXH@Z ; Derived::Print(int)
在 Derived vtable 中,GCC 和 MVSC 生成的二进制文件之间的Derived::Print(int)
和Derived::Print(double)
顺序相反。那么,为什么 GCC 和 MSVC 生成的二进制文件中的 vtable 中纯虚方法的顺序不同呢?另外,为什么只有在方法被覆盖时才会发生这种情况?
解决方案
推荐阅读
- android - 根据用户时区安排通知
- php - 如何解决“413 请求实体太大 nginx/1.1.19”错误?
- java - Spring Boot @CrossOrigin 不适用于 React 前端(带有授权标头)
- reactjs - 如何测试组件是否仅具有允许的道具并且仅使用 Jest 允许的类?
- c++ - 在抛出 'std::out_of_range' what(): array::at: __n (即 1990878449) >= _Nm (即 5) 的实例后调用终止
- python - 在网格数据上有效地找到要在空间和时间上跟踪的最近点
- ffmpeg - FFMPEG 拒绝通过 h264_nvenc 重新编码 vp9
- javascript - 如何在自定义函数中模拟 Axios?
- r - `across` 是否适用于 dplyr 火花帧的汇总?
- javascript - 如何在 ES6 中的 JSON 对象中添加累积值?