Detail C++ pure virtual functions and abstract classes

  • 2020-11-03 22:33:06
  • OfStack

1. The virtual functions

1.1 Introduction to virtual functions

One of the most important features of C++ can be described without exaggeration as 1. Let's start with 1 and look at the concept of virtual functions.

In the definition of base class, the general form of virtual function is defined as:


virtual  Function return value type   Virtual function name (table of parameters) 
{
  The body of the function 
}

Why are virtual functions one of the most important features of C++? Because virtual functions carry the role of dynamic linking in C++, namely polymorphism, which allows the program to select the appropriate member function at run time. Virtual functions must be non-static member functions (and non-constructors) of the class, with access to public. So:
(1) Why can't static member functions of a class be virtual functions?
If defined as a virtual function, it is dynamically bound, that is, overridden in a derived class, which contradicts the definition of a static member function (which has only one copy in memory and is accessed by class name or object reference).

(2) Why can't constructors be virtual functions?
Because if the constructor for the virtual function, it will be constructed during execution, and execution requires the object has been created, the constructor work done is to establish proper object, so in not build good cannot be performed on objects polymorphism (virtual functions is the purpose of realizing polymorphism). In inheritance, the order of construction is from base class to derived class to ensure that the object can be built successfully. Constructors also bear the responsibility of constructing virtual tables. If they are all virtual functions, how can they ensure the successful construction of virtual tables?

1.2 Virtual destructor

In class inheritance, base class destructor 1 is generally a virtual function. When there are virtual functions in the base class, destructors are also defined as virtual destructors. If a virtual destructor is not defined, when a pointer to a derived class object is deleted, the base class destructor is called, and the derived class destructor is not called, causing a memory leak.

The way virtual destructors work is that the destructor of the lowest derived class is called first, and then the destructor of the individual base class is called. This way, when a pointer to a derived class is removed, the derived class's destructor is called first and there are no memory leaks.

In general, there is no need to declare virtual destructors if there are no virtual functions in the class. Virtual destructors are declared if and only if the class contains at least one virtual function. It is only necessary to write destructors as virtual functions if a class is used as a base class.

1.3 Implementation of virtual functions -- Virtual function table

Virtual functions are realized through 1 table of virtual functions, abbreviated as ES32en-ES33en. Class is a contiguous block of memory, each memory cell recording the address of an JMP instruction. The compiler creates 1 vtable for each class that has a vfunction, which is Shared by all objects of the class, and each vfunction member of the class occupies 1 row in the vtable.

In this table, the address of a virtual function of a class is stored. This table solves the problem of inheritance and overwriting, ensuring that the actual virtual functions of the object can be accessed using base class Pointers or references to subclass object entities. In an instance with a virtual function class, memory is allocated to the pointer to the table, so when a parent class pointer is used to manipulate an object entity of a subclass, the virtual function table indicates the virtual function that should actually be called.

2. Pure virtual functions and abstract classes

Now that we have virtual functions, why do we need pure virtual functions? In Java programming language, there is the definition of interface. In C++, although there is no interface keyword, pure virtual function completes the function of interface. And sometimes when you write a base class, something like this happens:
(1) The function should not be completed by the base class;
(2) Haven't figured out how to write the base class function;
(3) Sometimes the base class itself should not be instantiated.

And that's where the pure virtual functions come in. Let's compare the difference between virtual functions and pure virtual functions through an example:


class Base 
{
public:
  // This is a 1 A virtual function 
  virtual void vir_func()
  {
   cout << "This is a virtual function of Base" << endl;
  }
  // This is a 1 A pure virtual function 
  virtual void pure_vir_func() = 0;
};

As can be seen above, the pure virtual function in the class does not define the function body, and added "= 0". A class that contains at least one pure virtual function is called an abstract class. The purpose of defining pure virtual functions and abstract classes is to define only the interfaces inherited by derived classes, and not to provide a reasonable default implementation for the time being. So the declaration of a pure virtual function is telling the designer of the subclass, "You have to implement this function, but I don't know how you're going to implement it."

It is worth noting that an abstract class cannot be instantiated because at least 1 function is not implemented, otherwise the compiler will report an error.

Let's look at an example of a pure virtual function versus an abstract class. This experiment was carried out in the environment of GNU C++.


#include <iostream>
using namespace std;

class Base
{
public:
  // This is a 1 A virtual function 
  virtual void vir_func()
  {
    cout << "This is a virtual function of Base" << endl;
  }

  // This is a 1 A pure virtual function 
  virtual void pure_vir_func() =0;
};

class Derive : Base
{
public:
  void vir_func()
  {
    cout << "This is a virtual function of Derive" << endl;
  }

  void pure_vir_func()
  {
    cout << "This is a pure virtual function of Derive" << endl;
  }
};

int main()
{
  // Base b; // The compiler reports an error when attempting to instantiate an abstract class 
  // b.vir_func();

  Derive d;
  d.vir_func();
  d.pure_vir_func();

  return 0;
}

Output:

[

This is a virtual function of Derive
This is a pure virtual function of Derive

]

The derived class Derive implements both virtual and pure virtual functions for the base class Base, while noting that the compiler complains when attempting to instantiate the abstract class.

1 In general, pure virtual functions do not have a body, but it is possible to give the body of a pure virtual function, so the following structure can be compiled:


class Base
{
public:
  // This is a 1 A virtual function 
  virtual void vir_func()
  {
   cout << "This is a virtual function of Base" << endl;
  }

  // This is a 1 A pure virtual function 
  virtual void pure_vir_func() =0
  {
   cout << "This is a pure virtual function of Base" << endl;
  }
};

But there is no point in doing so, because the abstract class cannot be instantiated and the method cannot be called.

These are the details of C++ pure virtual functions and abstract classes. For more information about C++ pure virtual functions and abstract classes, please pay attention to other related articles on this site!


Related articles: