Here's an example: https://godbolt.org/z/cKfn94MjP
In function f_derived compiler does not know what d pointer is. Maybe it is some other Derived2 class that inherits Derived and overrides return value of Foo. So it generates indirect branch from vtable (with extra optimizations) - load from vtable happens in lines 5/6 and jump to loaded function pointer in line 12.
But in function f_derived_final compiler sees that df pointer can only be DerivedFinal object in Foo call. Because nobody else can override Foo method even if somebody inherits DerivedFinal. So it simply inlines Foo() call - and no indirect branch happens. Code is simpler and smaller, and executes faster.