C++ 如果所有派生类在编译时都已知,final关键字是否提供优化?

C++ 如果所有派生类在编译时都已知,final关键字是否提供优化?,c++,performance,optimization,compilation,final,C++,Performance,Optimization,Compilation,Final,理论上,在C++11及以后的版本中,在虚拟方法声明中使用final关键字可以实现方法的内联 但是,我怀疑在实践中,如果在编译时知道没有派生类重写该方法,编译器可以为我们插入final,并内联该方法 这是为什么?优化方面,final只影响编译器是否能够在编译时证明派生类型。如果类型已知,则无需帮助编译器了解它 优化方面,final只影响编译器是否能够在编译时证明派生类型。如果类型已知,则无需帮助编译器了解它 C++11及以后版本中虚拟方法声明的final关键字允许方法的内联 不是内联,而是反虚

理论上,在C++11及以后的版本中,在虚拟方法声明中使用
final
关键字可以实现方法的内联

但是,我怀疑在实践中,如果在编译时知道没有派生类重写该方法,编译器可以为我们插入
final
,并内联该方法


这是为什么?

优化方面,
final
只影响编译器是否能够在编译时证明派生类型。如果类型已知,则无需帮助编译器了解它

优化方面,
final
只影响编译器是否能够在编译时证明派生类型。如果类型已知,则无需帮助编译器了解它

C++11及以后版本中虚拟方法声明的final关键字允许方法的内联

不是
内联
,而是反虚拟化

然而,我怀疑在实践中,如果在编译时知道没有派生类重写该方法,[…]

在编译时,您无法知道没有其他派生类(除非类是
final
):用户或其他TU可能会提供一些。假设没有动态加载,它可能在链接处完成

[…]编译器可以为我们插入一个final并内联该方法 然而,将其放入编译器资源管理器显示它仍然提供优化

 struct A {
     virtual void f() {}
 };

struct B : public A {
     void f() final override {}
 };

struct C : public A {
     void f() override {}
 };
void foo(B& b) { b.f(); }
void bar(C& c) { c.f(); }
为什么会这样

这里,当
C
的动态类型为
C
时,编译器内联调用
C::f
rep ret
): 然后,它不再调用
C::f
,而是做
C::f
所做的事情(->什么也不做)

虚拟调用仍然是对其他动态类型的调用(
jmp-rax

C++11及以后版本中虚拟方法声明的final关键字允许方法的内联

不是
内联
,而是反虚拟化

然而,我怀疑在实践中,如果在编译时知道没有派生类重写该方法,[…]

在编译时,您无法知道没有其他派生类(除非类是
final
):用户或其他TU可能会提供一些。假设没有动态加载,它可能在链接处完成

[…]编译器可以为我们插入一个final并内联该方法 然而,将其放入编译器资源管理器显示它仍然提供优化

 struct A {
     virtual void f() {}
 };

struct B : public A {
     void f() final override {}
 };

struct C : public A {
     void f() override {}
 };
void foo(B& b) { b.f(); }
void bar(C& c) { c.f(); }
为什么会这样

这里,当
C
的动态类型为
C
时,编译器内联调用
C::f
rep ret
): 然后,它不再调用
C::f
,而是做
C::f
所做的事情(->什么也不做)


虚拟调用仍然是对其他动态类型(
jmp-rax
)的调用。

“如果在编译时知道没有派生类”。你怎么知道的?我可以阅读代码,看到没有任何派生类。所以只能在link中完成,假设没有动态加载…啊,这就是我缺少的部分。因此,如果使用链接时间优化,编译器可能会自动将方法标记为
final
。如果你能在你的答案中加上一点关于只知道哪些派生类型在链接时可用的话,我会接受它,“如果在编译时知道没有派生类”。你怎么知道的?我可以阅读代码,看到没有任何派生类。所以只能在link中完成,假设没有动态加载…啊,这就是我缺少的部分。因此,如果使用链接时间优化,编译器可能会自动将方法标记为
final
。如果你能在你的答案中添加一点,只知道在链接时哪些派生类型是可用的,我会接受它。