生成的同名函数的vtable函数顺序反转

问题描述 投票:0回答:1

如果使用Visual Studio 2019,则使用两个具有相同名称但参数不同的虚拟方法来编译此C ++代码:

struct MyStruct
{
    virtual void foo(float) = 0;
    virtual void foo(int) = 0;
};

class MyClass : public MyStruct
{
public:
    void foo(float) {}
    void foo(int) {}
};

static MyClass c;

生成的类'vtable中的方法顺序颠倒了。这是https://godbolt.org

中的输出
const MyClass::`vftable' DQ FLAT:const MyClass::`RTTI Complete Object Locator'          ; MyClass::`vftable'
    DQ      FLAT:virtual void MyClass::foo(int)
    DQ      FLAT:virtual void MyClass::foo(float)

如果我区分名称(如foo1和foo2),则生成代码中的顺序与声明中的顺序相同。

这是C ++编译器的正常行为吗?如果是,如何确定订单?

c++ visual-c++ virtual-functions vtable
1个回答
0
投票

简短(无助)的答案是,vtable的布局肯定在编译器中。实际上,语言标准不需要编译器甚至使用vtable来实现虚拟函数的分派。

也就是说,在Windows和Visual C ++的特定情况下:

  • [C ++ vtables刻意布置成与COM调用约定兼容,这要求为虚拟功能顺序分配插槽;

  • 对于COM互操作,简单继承也会在父vtable的末尾追加新的虚函数;

  • 但是,COM不允许重载,即具有不同签名的同名函数。

OP的大小写违反了最后一点,因此COM保证不适用于此处,因为由于重载,该接口最初与COM不兼容。实际上,Microsoft明确警告C#为avoid overloads in COM visible interfaces

因此从技术上讲,VC ++编译器的行为不会违反任何规则,无论是语言还是COM。另外,我不知道有任何选项/技巧/手段可以在vtable中强制执行特定顺序的重载。

[一种可能的(虽然不是很漂亮的)解决方法是在继承树中引入一个人为的额外类,以便每个新派生仅添加一个唯一的重载。

struct MyHiddenStruct
{
    virtual void foo(float) = 0; 
};

struct MyStruct : MyHiddenStruct
{
    MyHiddenStruct::foo;
    virtual void foo(int) = 0; 
};

class MyClass : public MyStruct
{
public:
    void foo(float) { }
    void foo(int) { }
};
© www.soinside.com 2019 - 2024. All rights reserved.