为具有相同名称的函数反转生成的vtable函数顺序



如果使用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++编译器的正常行为吗?如果是,顺序是如何决定的?

简单的答案是vtable的布局当然取决于编译器。事实上,语言标准甚至不要求编译器使用vtables来实现虚拟函数调度。

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

  • C++vtables的布局是有意的,以便与COM调用约定兼容,COM调用约定要求为虚拟函数顺序分配插槽;

  • 同样对于COM互操作,简单继承在父vtable的末尾添加新的虚拟函数;

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

OP的情况违反了最后一点,因此COM保证在这里不适用,因为由于重载,接口一开始就不兼容COM。事实上,微软明确警告C#避免COM可见接口中的过载。

因此,从技术上讲,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) { }
};

[编辑];发现了类似的VS 2010 q&a在vfptr中的Visual C++方法中以相反的顺序显示,并强烈提示同一类中的重载在vtable中以声明的相反顺序分组在一起。因此,无论VS 2019如今做什么,它都不是一个新的突发奇想。

最新更新