Virtual Method

Virtual Method Table (VMT)

This is how polymorphic calls are implemented in C++.

It’s also important to understand how this works for Virtual Inheritance.

I found the best explanation here: https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/.

How Dynamic Dispatching is achieved

The 3 steps taken at run-time in order to achieve dynamic dispatch for virtual functions are:

  1. Locate the virtual pointer (vptr): when a call to a virtual function on an object is performed, the vptr of the object is used.
  2. Locate the Virtual Table (vtable): The vptr leads to the vtable of the class.
  3. Call the Virtual Function: The vtable contains pointers to the virtual functions for that class, which is how we can call those functions.

Notes from CS247

Though this is sometimes slightly confusing. See Virtual Method first.

struct Vec2 {
	int x,y;
	virtual void doSomething();
}
 
struct Vec3: public Vec2 {
	int z;
	void doSomething() override;
}
 
string choice;
cin >> choice;
Vec2* v;
if (choice == "Vec2")  {
	v = new Vec2{...};
} else {
	v = new Vec3{...};
}
v->doSomething();

For the code above, we have the following vptr and vtable layout:

When we create a vec2 or vec3, we know what type of object we’re creating, so we can fill in the appropriate vptr for that object.

When you call v->doSomething(), the pointer v will be pointing to either an object of type vec2 or vec3.

  • in either case, we can simply follow the vptr of that object, get to the vtable, and find the function address for the doSomething method.

Warning

There is extra running time cost in the time it takes to follow the vptr and access the vtable.

There is a single virtual pointer (vptr) per object, not per virtual function.

C++ Philosophy: Don’t pay for costs unless you ask for it.

I still need to fully understand how the vtables are implemented.

Virtual Static Functions CANNOT exist

This is also why a virtual function cannot be global or static because, by definition, a virtual function is a member function of a base class and relies on a specific object to determine which implementation of the function is called.

More details here with vpointers and vtables: