虚函数效率和“final”关键字

Con*_*uit 3 c++ performance vtable c++11

考虑一个程序,它有一个类,其中包含如下声明的Foo函数:Foo::fn

virtual void fn();
Run Code Online (Sandbox Code Playgroud)

和一个Foo名为 的子类Bar。将Bar::fn这样声明:

virtual void fn() override final;
Run Code Online (Sandbox Code Playgroud)

导致对fninBar或 的子类的调用Bar更加有效,还是只会阻止 的子类Bar被覆盖fn?如果使用 使调用更加高效final,那么最简单、最有效的定义方法是什么,Bar::fn使其功能与 完全相同Foo::fn

Cas*_*sey 6

如果fn定义为finalin ,编译器可以通过指针或静态引用Bar调度调用,因为它知道这是最终的重写器。例如这个程序片段:fnBarBar::fn

struct Foo {
  virtual void fn();
};

struct Bar : Foo {
  void fn() final override;
};

void with_foo(Foo& o) { o.fn(); }
void with_bar(Bar& o) { o.fn(); }
Run Code Online (Sandbox Code Playgroud)

编译为(有关详细信息,请参阅 gcc.godbolt.org):

with_foo(Foo&):
    subq    $8, %rsp
    movq    (%rdi), %rax
    call    *(%rax)
    addq    $8, %rsp
    ret

with_bar(Bar&):
    subq    $8, %rsp
    call    Bar::fn()
    addq    $8, %rsp
    ret
Run Code Online (Sandbox Code Playgroud)

in 中的调用是通过 vtablewith_foo动态分派的(是间接调用),但 in 中的调用是静态分派到.call *(%rax)with_barBar::fn()

在不改变行为Bar::fn的情况下成为最终重写者的最简单方法是将其定义为静态调用:Foo::fnFoo::fn

struct Bar : Foo {
  void fn() final override { Foo::fn(); }
};
Run Code Online (Sandbox Code Playgroud)