devxlogo

Virtual function tables

Virtual function tables

Question:
I would like to know what virtual function tables are. When one refers to vtables, is it a virtual function table that is implied?

Answer:
In short, vtables are how most C++ compilers implement polymorphism, which means to take on many forms. In the context of C++, it is when you do not have full knowledge of the type (class) at compile time.

In essence, you have a pointer to a base class at compile time that will point to a derived class instance at runtime. Next, the function your base class pointer is calling is dynamically binded at runtime to the derived class instance that your base class pointer is referencing.

For this to be possible, you must define such functions as virtual in the base class. As a result, all derived classes will also treat such member functions as virtual (see code extract below).

In your code somewhere, the following classes are defined:

Canine is the base class, and Dog and Wolf derive from Canine. Notice the Bark member function is declared as virtual. You could include the virtual keyword in Dog and Wolf for clarity, but it isn’t necessary. Once a function is defined as virtual in a base class, it will be virtual in all base class descendants, as is the case in Dog and Wolf.

class Canine{public:	virtual void Bark( ) { cout << "do nothing" << endl; }	...};class Dog : public Canine{	void Bark( ) { cout << "dog bark." << endl; }};class Wolf: public Canine {	void Bark( ) { cout << "wolf bark" << endl; }
Next, you may contain consumer code similar to the following:
//somewhere in my code.cpp file…void StartBarking(Canine* pCanine){	pCanine->Bark( );}void main ( ){// Imagine the canine types coming from a collection or database at runtimeDog* pDog =3D new Dog;Wolf* pWolf =3D new Wolf;// Next, your code simply reads those values in and calls the StartBarking function, which you have defined.StartBarking( pDog );StartBarking( pWolf );…}
Based on the code extract above, the StartBarking function takes a pointer to the Canine object. Canine is the base. The compile time code looks like this:
pCanine->Bark( );
At runtime, however, pCanine could be pointing to any descendent of the Canine class; hence, without you having to explicitly identify which Canine it is, the compiler will dynamically bind the appropriate Bark function to the Canine descendent class instance that pCanine is referencing. Remember, this is possible because the Bark function is defined as virtual in the Canine base class. If Bark was not defined as virtual, polymorphism would not exist because although the base class pointer is pointing to an instance of a descendent class, it would be unaware of the Bark function in the descendent, and would call the base class version instead, producing an undesirable result.
See also  Why ChatGPT Is So Important Today

The virtual keyword indicates to the C++ compiler that it must create a vtable for the base class and all other classes that derive from it. A vtable is table in memory of pointers to functions defined as virtual in a given class, thus the name vtable (virtual function table).

There will always be one vtable per class (type) in memory. Each instance of the same class contains a pointer to the same vtable. Said another way, multiple objects of the same type share the same vtable. At runtime, pCanine will determine if the function being invoked is virtual. If so, it looks in the vtable of the object instance it is referencing, which will contain a pointer to the function that must be invoked.

When you re-implement a virtual function in a derived class, you are doing what is referred to as overriding the behavior of the base class function, which is what has been illustrated in code example above (both Dog and Wolf override the Bark virtual function). However, you may find in some cases that there is no need to override a virtual function if the descendent simply performs the same behavior as its ancestor (base) class.

Whether you override a virtual function in a derived class or not, it will have its own vtable with the same amount of entries as its base class. The difference is, virtual functions that are overridden will have pointers to functions in the vtable that refer to unique addresses, but virtual functions that are not overridden with have pointers to functions with the same address of the virtual functions originally defined in the base class. Therefore, keep in mind that utilizing polymorphism in C++ has the overhead of a vtable in memory for each class that contains virtual functions, and classes that derive from classes that contain virtual functions,whether or not you override those functions. However, this is a small price to pay to have a true object-oriented application, which essentially does not exist without polymorphism.

See also  Professionalism Starts in Your Inbox: Keys to Presenting Your Best Self in Email
devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist