Method 1: Flat VTable.
All virtual methods of a class type (including inherited methods) are represented in a table of method pointers, one for each virtual method. Invocation requires calling indirect through the method pointer at a fixed offset in the table. Each new class creates its own vtable, copies the vtable of its ancestor, overwrites the pointers for virtual methods overriden in the class with pointers to the new methods, and adds new virtual methods defined in the class at the end of the table.
Method 2: Linked VTable (aka dynamic method table)
Only the virtual methods declared or overridden in a class type occupy space in a linked vtable. Each method is assigned an id, and the id and method pointer are stored together in the dynamic method table. Invocation requires scanning the dynamic method table looking for a match for the virtual method id. If no match is found, the scan continues with the class's immediate ancestor's dynamic method table, and so on until either a match is found or you run out of ancestors.
Method 3: Message passing. No formal table of method pointers is generated by the compiler. Rather, each virtual method is assigned a unique id and invoked via a dispatch function. The dispatch function can be simply a case / switch statement on method ids. Case blocks may call individual methods of the object or may implement the behavior directly.
Dynamic method tables are actually a hybrid of traditional vtables and message passing. Pure message passing typically has little or no expectation of what the arguments are for the call. The Windows WndProc is an example of message passing, and replacing the wndproc pointer of a window handle is the means of hooking or overriding default behaviors. The WndProc has a fixed argument structure into which all messages must find a way to attach their specific parameter data.
The strength of message passing is flexibility, but often at a performance cost. VTable virtual methods are very fast to dispatch (simply a call indirect) but are very inflexible once established. Since each class VTable includes slots for all inherited virtual methods, VTables require more memory than dynamic method tables, especially in deep object hierarchies.
In the Delphi programming language, virtual methods are implemented using VTables, dynamic methods are implemented using dynamic method tables, and WndProcs use message passing.