Sure, virtual calls have some runtime overhead. But when you use virtual functions, it's usually not a choice but a consequence of the problem you are solving. If you need to call a function on a type-erased value there isn't a real alternative, unless we count some C-style void*
approaches.
This runtime overhead is typically just a memory load to retrieve the vtable pointer, and another load to read the vtable entry for the indirect call. There are cache implications, though at least the vtable has a good chance of being cached when performing multiple operations with the same type.
One level of indirection can be removed by using a fat pointer design where the vtable pointer is stored alongside the data pointer, instead of within the data. While this strategy is used by Go and Rust implementations, it's unsuitable for C++ implementations. You could do this yourself (by modelling the vtable as a struct of function pointers) but you do give up a lot of typesafety regarding inheritance.
In some rare cases, usage of inheritance and virtual functions is actually unnecessary in C++. This is a multi-paradigm language, and the OOP paradigm is not necessarily the most suitable. E.g. when we need polymorphism but all types are statically known, a template- or overload-based solution might be more appropriate. But that really depends on the problem, you can't categorically replace virtual calls. There are also significant tradeoffs. While templates tend to allow for better optimizations (can't optimize a across virtual calls), they also tend to lead to bloated and redundant code that is cache-unfriendly.
So: please don't worry about virtual calls. They are a really good feature, and likely a lot faster + safer than DIY fixes. Instead, consider whether you have a suitable data model, e.g. whether it is appropriate to use type erasure at all. Other optimization approaches like profile-guided optimization or link-time optimization are likely to have a much larger overall effect, unless you have a ton of virtual calls in a very very hot loop.
If you are going to descend into performance paranoia, please also consider that a dynamically linked function call has similar performance implications to a virtual call. Yet, I don't see a lot of people arguing that you should stop using dynamically linked libraries for performance reasons.