如果使用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 ++ 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) { }
};