首页 > 解决方案 > 为什么 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):

.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)
.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 中纯虚方法的顺序不同呢?另外,为什么只有在方法被覆盖时才会发生这种情况?

标签: c++polymorphismdisassembly

解决方案


推荐阅读