It depends on how you pass the instance around. Consider in one translation unit:
Derived d;
foo( &d );
and in another:
void foo( Base* b )
{
b->foo();
}
except for LTO, there is no chance for the compiler to remove the virtual call overhead.
If OTOH, you have:
void foo( Derived* d )
{
d->foo();
}
The compiler could now be smart enough to optimize the vtable lookup away as it has all the necessary information. I don't think it is guaranteed, though. Without final, the vtable lookup would still be necessary as d
could point to something derived from Derived
which has yet another implementation of foo_impl()
.