Suppose you have this class:
class X {
public:
virtual void myfunc();
};
If you call the virtual function for a plain object of type X, the compiler will generate a direct call, i.e. refer directly to X::myfunct()
:
X a; // object of known type
a.myfunc(); // will call X::myfunc() directly
If you'd call the virtual function via a pointer dereference, or a reference, it is not clear which type the object pointed to will really have. It could be X but it could also be a type derived from X. Then the compiler will make a virtual call, i.e. use a table of pointers to the function address:
X *pa; // pointer to a polymorphic object
... // initialise the pointer to point to an X or a derived class from X
pa->myfunc(); // will call the myfunc() that is related to the real type of object pointed to
Here you have an online simulation of the code. You'll see that in the first case, the generated assembly calls the address of the function, whereas in the second case, the compiler loads something in a register and make an indirect call using this register (i.e. the called address is not "hard-wired" and will be determined dynamically at run time).