A virtual table, or "vtable", is a mechanism used in Programming languages to support dynamic polymorphism, i.e., run-time method binding. Hope ive helped.
Each function has an address in memory somewhere. Function names are just pretty ways of referring to a position in memory. When a program is linked (after the compiler is finished compiling) all those names are replaced with hardcoded memory addresses.
class Foobar
{
public:
};
int main()
{
}
You can tell even before execution that f.Something() is referring to the Something in Foobar. The linker will be able to replace that with an address pointing directly at Something.Draw().
This works pretty well until you bring in polymorphism because the linker is unable to tell which function to call. For example in C++:
class Foobar
{
public:
};
class Foo: public Foobar
{
public:
};
class Bar: public Foobar
{
public:
};
void FoobarFunc(Foobar* fb)
{
}
void FooFunc(Foo* f)
{
}
int main()
{
}
In this excerpt, both Foo and Bar inherit from Foobar. FuncA is a virtual function while FuncB is not. The integer i is being set to see the results of our actions.
Notice how in FoobarFunc, you are unable to tell beforehand what address to replace FuncA and FuncB with! In order to solve this, virtual tables are created.
Normally, functions are not stored with the data of the class at all. So in our very first Foobar example with no inheritance, the class would only be 4 bytes long (excluding any compiler magic). However, when you declare something virtual, you're actually declaring a pointer to a function so each virtual function you have will increase the class size by the size of a pointer. The pointers will be populated by the constructors under the hood which is one reason why you cannot have virtual constructors. If you have many virtual functions, you end up with many pointers, which are organized into a table... the v-table. Each class will have its own unique v-table.
When a child class is constructed, the parent class's constructor is called before the child class's constructor is called. Each classes constructor will put the addresses of all the virtual functions it has into the v-table. In our example, when Foo is instantiated, Foobar's constructor is called first. Foobar's constructor will place the memory location of Foobar.FuncA into the v-table. Once Foobar's constructor is done, Foo's constructor will execute, placing Foo.FuncA into the table.
In FoobarFunc the line fb->FuncA(), actually replaced by an address to the v-table. When that line is executed, the computer will go to that location in the v-table, fetch the address of the function, and then jump to that location in memory. Because of how the constructors setup the v-table, you end up calling the correct function.
If you look at the example, you'll notice I have included FuncB which is not declared virtual to highlight the difference between virtual and nonvirtual functions. In FoobarFunc, the parameter is Foobar. Because FuncB is not virtual, there is no entry for FuncB in the v-table. The compiler/linker will hardcode the address in the binary and cause the program to always execute Foobar.FuncB no matter what gets passed in as the parameter. No polymorphism. In FooFunc, the parameter is Foo. Foo.FuncB will always execute in that function. Again, no polymorphism.