如果使用 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 的布局肯定是由编译器决定的。事实上,语言标准甚至不要求编译器使用 vtable 来实现虚拟函数调度。
也就是说,在 Windows 和 Visual C++ 的特定情况下:
C++ vtable 是经过精心设计的,以便与 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) { }
};
[ EDIT] 在以下位置找到了类似的 VS 2010 问答vfptr 中的 Visual C++ 方法按相反顺序排列强烈暗示同一类中的重载以与声明相反的顺序分组在 vtable 中。所以无论 VS 2019 现在做什么,这都不是一个新的突发奇想。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)