为同名函数生成的 vtable 函数顺序反转 [英] Inversion of generated vtable functions order for functions with the same name

查看:24
本文介绍了为同名函数生成的 vtable 函数顺序反转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If, using Visual Studio 2019, I compile this C++ code with two virtual methods having the same name but different arguments:

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

The order of methods in the generated class' vtable is inverted. Here is the output in 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),生成的代码中的顺序与我的声明中的顺序相同.

If I differentiate names (like foo1 and foo2), the order in generated code is the same as in my declaration.

这是 C++ 编译器的正常行为吗?如果是,顺序是如何决定的?

Is this normal behavior for a C++ compiler? If yes, how is the order decided?

推荐答案

简而言之,vtable 的布局肯定是编译器向上的.事实上,语言标准甚至不需要编译器使用 vtables 来实现虚函数调度.

Short answer is that the layout of the vtable is certainly up the compiler. In fact, the language standard does not require the compiler to even use vtables for implementing the virtual functions dispatch.

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

That said, in the particular case of Windows and Visual C++:

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

  • C++ vtables are deliberately laid out such as to be compatible with the COM calling conventions, which require the slots to be sequentially assigned for virtual functions;

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

also for COM interop, simple inheritance appends new virtual functions at the end of the parent vtable;

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

however, COM does not allow overloads i.e. namesake functions with different signatures.

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

OP's case violates the last point, so the COM guarantees do not apply here, because the interface is not COM compatible to begin with, due to the overloads. In fact, Microsoft explicitly warns for C# to avoid overloads in COM visible interfaces.

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

So technically the behavior of the VC++ compiler does not break any rules, either language or COM. Also, I am not aware of any option/trick/recourse to force a particular order of the overloads in the vtable.

一种可能(虽然不是很好)的解决方法是在继承树中引入一个人为的额外类,这样每个新派生只会增加一个唯一的重载.

One possible (though not pretty) workaround could be to introduce an artificial extra class in the inheritance tree, so that each new derivation only adds a unique overload.

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) { }
};

<小时>

[ 编辑 ]  在 vfptr 中的 Visual C++ 方法反向找到了一个类似的 VS 2010 q&aorder 强烈暗示同一类中的重载以声明的相反顺序组合在 vtable 中.所以无论 VS 2019 现在做什么,都不是一个新奇的想法.


[ EDIT ]   Found a similar VS 2010 q&a at Visual C++ methods in vfptr in reverse order with a strong hint that overloads in the same class are grouped together in the vtable in the reverse order of declaration. So whatever VS 2019 does nowadays, it's not a new whim.

这篇关于为同名函数生成的 vtable 函数顺序反转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆