In theory, using the final
keyword on a virtual method declaration in C++11 and onwards allows inlining of the method.
However, I suspect that in practice, if it is known at compile time that there are no derived classes overriding that method, the compiler can insert a final
for us and inline the method.
However, putting this into compiler explorer shows that it still provides optimizations.
Why is this?
final keyword on a virtual method declaration in C++11 and onwards allows inlining of the method
Not inlining
, but de-virtualization.
However, I suspect that in practice, if it is known at compile time that there are no derived classes overriding that method, [..]
You cannot know at compile time that there are no other derived classes (unless class is final
): user or other TU might provide some. it might potentially be done at link, supposing no dynamic loading...
[..] the compiler can insert a final for us and inline the method However, putting this into compiler explorer shows that it still provides optimizations.
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::f(): rep ret foo(B&): rep ret bar(C&): mov rax, QWORD PTR [rdi] mov rax, QWORD PTR [rax] cmp rax, OFFSET FLAT:C::f() jne .L6 rep ret .L6: jmp rax
Why is this?
Here, compiler inlines call of C::f
(rep ret
) for the case when dynamic type of c
is C
:
then instead of calling C::f
, it does what C::f
does (-> nothing).
virtual call is still call for other dynamic type (jmp rax
).