You are probably prematurely optimizing here, you should design your system for optimum usability before worrying about the overhead for a function call. It's probably not going to be a performance bottleneck anyway unless you are sending hundreds of thousands of events per second.
It depends on the hardware, but even a few hundred thousand "per second" is not an issue.
In games, you are interested in "per frame", not "per second".
For a 60fps target you have 16.6 million nanoseconds per frame, double that for a 30fps target. That is your maximum time budget.
A few seconds on Google shows that for desktop processors over the last decade --- all with branch prediction, speculative execution, and out-of-order cores --- the average cost of a virtual function call is 2.4 cycles to 4.8 cycles depending on the processor. In nanoseconds that is between 1.1ns and 2.1ns. That is all on a single core, most machines have anywhere from 2-24 CPU cores on them.
Over the years I have spent many months on-and-off during various projects performing optimization passes. In our major titles that can reach high framerates we can easily afford many thousand virtual functions per frame. It is not a performance issue to use them intelligently.
That doesn't mean you can use virtual functions stupidly. They absolutely have a small cost. They require a few nanoseconds. They cannot be inlined, so you must pay the price of calling and returning from a function. It would be foolish indeed to make every function virtual, especially in classes that will never be overridden such as a Vector3 or Matrix44 class. But what are the alternatives when you actually need them? Virtual functions solve very real programming problems.
The first common scenario is that you need to modify execution based on state, also known as dynamic dispatch. Generally the state is a subclass. You can either implement a giant switch statement, or an if/else tree, but neither is extensible. You can either implement your own vtable / jump table, or you can rely on the heavily optimized built in virtual functions.
The second common scenario is that you need to implement interfaces, also known as abstract base classes or pure virtual functions. This is necessary to follow the excellent design principle of dependency inversion. Again you can either implement a non-maintainable switch statement or if/else tree, or you can implement your own vtable / jump table, or you can rely on the built in virtual functions.
Delegates like this are doing exactly the same thing as a vtable lookup. They have essentially the same performance characteristics, although some poor implementations may require a few extra nanoseconds. A cost, certainly, but a trivial one.
Virtual functions, function pointers, and delegates are very useful and solve very real problems. They are already optimized to use less CPU cycles than complex operations like floating point division. Use them.