Virtual functions

Virtual functions, virtual Pointers, and virtual tables

  • Virtual functions: Functions declared with the virtual keyword are called virtual functions. Virtual functions must be member functions of the class.
  • Virtual Pointers and virtual tables: Every class that has virtual functions has a one-dimensional virtual table called the virtual table. Each class object has a virtual pointer to the start of the virtual table. Virtual tables correspond to classes, and virtual table Pointers to objects.

Virtual function implementation principle

The vtable is a one-dimensional array (rather than a linked list) containing the addresses of each virtual function. Since both Base and Derive contain a virtual function func(), the compiler creates a virtual table for both classes.

So how do you locate a virtual table? The compiler also automatically creates a virtual table pointer (VPTR) for each object of a class with a virtual function, which points to the virtual table of the class to which the object belongs. When the program runs, the VPTR is initialized according to the type of the object, so that the VPTR correctly points to the virtual table of the class it belongs to. So when a virtual function is called, the correct function is found.

In the case of the above program, since the actual object type referred to is Derive, the vtable of Derive is referred to by VPTR, and when func() is called, the func() function of Derive is found based on the function address in the virtual table.

Because every virtual function called by an object is indexed by a virtual table pointer, proper initialization of the virtual table pointer is very important. In other words, we cannot call a virtual function until the virtual table pointer is properly initialized. So when, or where, is the virtual table pointer initialized? The answer is to create the virtual table and initialize the pointer to the virtual table in the constructor.

When a subclass object is constructed, the superclass constructor is called first, and then the subclass constructor is completed. When the constructor of the parent class is called, the compiler only “sees” the parent class and does not know if there is any successor. It initializes the virtual table pointer to the parent’s virtual table. When the constructor of a subclass is executed, the virtual table pointer is reassigned to its own virtual table. In the example above, when the object of Derive is constructed, its internal virtual table pointer is initialized to point to the virtual table of Derive. After the cast, you call func(), which ends up calling the func() function of Derive because you’re actually pointing to an object of Derive, and the virtual table pointer inside that object points to a virtual table of Derive.

Note: For virtual function calls, each object has a pointer to a virtual table that is initialized to the virtual table of the class. So in your program, no matter how your object type is converted, the pointer to the virtual table inside the object is fixed, so you can make dynamic object function calls. This is how polymorphism is implemented in C++.

Virtual and pure virtual functions

  • The main function of virtual function is to establish abstract model, facilitate system expansion, understand the polymorphism of virtual function + inheritance implementation;
  • A pure virtual function is a special kind of function, which is marked as a function without concrete implementation.
  • Virtual functions must be non-static members of the class and can be public or protected.
  • Pure virtual functions are a subset of virtual functions used for abstract classes. A class containing pure virtual functions is an abstract class. It cannot generate objects.
  • In many cases, it is not reasonable for the base class itself to generate objects. For example, an action as a base class can derive a specific animal, such as a monkey or a tiger, but it is obviously not reasonable for the animal class itself to generate objects.
  • In order to solve the above problems, pure virtual functions are introduced and defined as pure virtual functions. The compiler requires that the derived classes must be overloaded or overridden to achieve polymorphism. Classes that contain pure virtual functions cannot generate objects;

An abstract class

  • Abstract classes cannot be instantiated;
  • An abstract class must implement its methods by inheriting derivations; You can’t use the new keyword on an abstract class, nor can it be encapsulated;
  • Abstract classes must contain pure virtual functions;