在下面的代码中,它通过指向派生对象的指针调用虚函数foo.这个电话会通过vtable还是B::foo直接打电话?
如果它是通过vtable进行的,那么B::foo直接调用它的C++惯用方法是什么?我知道在这种情况下我总是指着一个B.
Class A
{
public:
virtual void foo() {}
};
class B : public A
{
public:
virtual void foo() {}
};
int main()
{
B* b = new B();
b->foo();
}
Run Code Online (Sandbox Code Playgroud)
如果启用了优化,大多数编译器都会足够智能,以消除该场景中的间接调用.但只是因为你刚刚创建了对象并且编译器知道动态类型; 可能存在您知道动态类型而编译器不知道的情况.
像往常一样,这个问题的答案是"如果它对你很重要,那就看看发出的代码".这就是g ++在没有选择优化的情况下生成的:
18 b->foo();
0x401375 <main+49>: mov eax,DWORD PTR [esp+28]
0x401379 <main+53>: mov eax,DWORD PTR [eax]
0x40137b <main+55>: mov edx,DWORD PTR [eax]
0x40137d <main+57>: mov eax,DWORD PTR [esp+28]
0x401381 <main+61>: mov DWORD PTR [esp],eax
0x401384 <main+64>: call edx
Run Code Online (Sandbox Code Playgroud)
这是使用vtable.直接调用,由以下代码生成:
B b;
b.foo();
Run Code Online (Sandbox Code Playgroud)
看起来像这样:
0x401392 <main+78>: lea eax,[esp+24]
0x401396 <main+82>: mov DWORD PTR [esp],eax
0x401399 <main+85>: call 0x40b2d4 <_ZN1B3fooEv>
Run Code Online (Sandbox Code Playgroud)
是的,它将使用 vtable(只有非虚拟方法绕过 vtable)。如需直接致电B::foo(),b请致电b->B::foo()。