Since the question is "Is there a performance hit?" and not "Can there be a performance hit?", it is surprisingly tricky to answer accurately. This is because compilers are given a lot of leeway when it comes time to optimize your code, and they often make use of it. The process of eliminating that specific overhead has a particular name: devirtualization.
Because of this, whether a cost is incurred or not will depend on:
- Which compiler is being used
- The compiler version
- The compiler settings
- The linker settings
- How the class is used
- Whether there are any subclasses that override the method.
So what should you do with so much uncertainty? Since the overhead is minor in the first place, the first thing is to not worry about it unless you need to improve performance in that specific area. Writing structurally sound and maintainable code trumps premature optimisation every single time.
But if you have to worry about it, then a good rule of thumb is that if you are calling a non-final virtual function from a pointer or reference (which includes this) to a non-final class, then you should write code with the assumption that the tiny overhead associated with an indirect lookup through a vtable will be
paid.
That doesn't mean that the overhead will necessarily occur, just that there is a non-zero chance that it will be there.
So in your scenario, given:
class Base {
public:
virtual void foo() { std::cout << "foo is called\n"; }
void bar() { foo(); }
};
int main() {
Base b;
b.bar();
}
Base is not final
Base::foo is not final.
this is a pointer.
So you should operate under the assumption that the overhead might be present, regardless of whether or not it ends up being there in the final built application.