It's sometimes easier to understand with an example:
class PureVirtual {
public:
virtual void methodA() = 0;
virtual void methodB() = 0;
};
class Base : public PureVirtual {
public:
virtual void methodA();
void methodC();
private:
int x;
};
class Derived : public Base {
public:
virtual void methodB();
private:
int y;
};
So, given an object of type Derived it might look like:
------------
Known offset for vtable | 0xblah | -------> [Vtable for type "Derived"]
------------
Known offset for x | 3 |
------------
Known offset for y | 2 |
------------
With the Vtable for type "Derived" looking something like:
------------
Known offset for "methodA" | 0xblah1 | ------> methodA from Base
-------------
Known offset for "methodB" | 0xblah2 | ------> methodB from Derived
-------------
Note that since "methodC" was not virtual, it is not in the vtable at all. Also note that all instances of class Derived will have a vtable pointer to the same, shared vtable object (since they have the same type).
Though the implementations for C++ and Java are slightly different, the ideas are not incompatible. The key difference, from a conceptual standpoint, is that Java methods are "virtual" unless declared "final". In C++ the keyword "virtual" must be given explicitly for the function to be in the vtable. Anything not in vtable will be dispatched using the compile-time types rather than the runtime type of the object.