Even if the method is virtual, C++ compilers make an effort to call methods directly without indirection through a vtable wherever possible.
A long term ambition for C++ and more specifically for Bjarne has been UFCS, Universal Function Call Syntax, which a few other languages have. But C++ can't do this today.
Example: https://godbolt.org/z/6Y1raxMce
``` struct foo { void bar(); }
bar(foo* i) { assert(i != nullptr); i->bar(); } ```
work, but there's enough syntactic complexity in the language that it isn't as easy as it should be.
In this case, the addresses of all the methods are known at compile time and the compiler knows which to choose when anyone is invoked in the source code, based on the type of the object and on the types of the method arguments.
When there is at least one "virtual" method and you have a pointer to an object, the type of the object cannot be known at compile-time, so the compiler cannot determine which method to invoke.
That is why the compiler needs to create a table with pointers to the virtual methods for each class with such methods, and each object of those classes must include a pointer to the corresponding vtable, so that the correct method to invoke can be determined at run time (from the index of the virtual method).
https://en.cppreference.com/w/cpp/language/object#Polymorphi...