Inversion of generated vtable functions order for functions with the same name

本小妞迷上赌 提交于 2021-02-11 13:56:38

问题


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;

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)

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

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


回答1:


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.

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

  • 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;

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

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

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.

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

[ 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.



来源:https://stackoverflow.com/questions/61542063/inversion-of-generated-vtable-functions-order-for-functions-with-the-same-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!