通常我们会认为 c++ 程序中,类的虚函数总是严格按照类中的声明顺序排列,但最近我在查看一个虚函数的调用时却发现并不如此。如果虚函数有候选的重载,那它的顺序实际可能和声明的顺序不一样。
比如下面一个简单的类
class VTableOrder {
public:
virtual int F1(int) { return 1; }
virtual int F2(int) { return 2; }
virtual int F3(int) { return 3; }
virtual int F2(int*) { return 4; }
void FF(char) {}
virtual ~VTableOrder() {};
private:
int a, b, c;
};
int main() {
VTableOrder* p = new VTableOrder();
return 0;
}
在类的声明顺序中,F2(int*) 排在第四个,但用 msvc 编译出来后发现实际位置是在第二个。

观察图中的虚函数地址,可以看到虽然顺序变了,但是函数的地址还是按声明的顺序从小到大排列的,F2(int*) 仍然排在第四。
如果把 F2(int) 和 F2(int*) 的位置互换,发现它们在虚表中的顺序也换过来了。看起来只是单纯的后进先出,不像是有特定的排序规则,比如按名称粉碎后的字典序排列等。

因此看汇编代码时也需要留意,不能想当然地按函数的声明顺序来对比。
