Detail virtual functions in C++ programming

  • 2020-05-05 11:34:28
  • OfStack

We know that you cannot define two functions with the same name, the same number of arguments, and the same type in the same class. However, in the inheritance hierarchy of a class, functions with the same name, the same number of arguments, and the same type can appear in different levels with different functions.

The idea has been put forward as to whether a function of the same name can be called from a derived class as well as from a base class in the same invocation form. Instead of calling functions of the same name in different derived levels with different object names in a program, you call them with Pointers. For example, use the same statement "pt-> display ();" You can call the display function in different derived levels simply by assigning a different value to the pointer variable pt (pointing to a different class object) before calling it.

For example, if you want to go somewhere for business, if you take a bus, you must determine your destination in advance, and then take the bus route to get there. If you take a taxi instead, it's much easier. You don't have to check the route, because a taxi can go anywhere. Just tell the driver where to go once you get on the bus. If you want to visit multiple destinations, just tell the driver the next destination after arriving at one destination. Obviously, taking a taxi is more convenient than taking a bus. You can take the same taxi wherever you go. This is an example of how one form can serve different purposes.

The virtual function in C++ is used to solve this problem. Virtual functions allow you to redefine functions with the same name as the base class in a derived class, and you can access functions with the same name in the base class and derived class through a base class pointer or reference.

Analyze the following example. This example starts without using virtual functions, and we'll discuss them later.

The base class and the derived class have functions of the same name. In the following program, Student is the base class and Graduate is the derived class, both of which have the same name as display.


#include <iostream>
#include <string>
using namespace std;
// Statement of the base class Student
class Student
{
public:
  Student(int, string,float); // Declaration constructor 
  void display( );// Declare output function 
protected: // A protected member that can be accessed by derived classes 
  int num;
  string name;
  float score;
};
//Student Class member function implementation 
Student::Student(int n, string nam,float s)// Define the constructor 
{
  num=n;
  name=nam;
  score=s;
}
void Student::display( )// Define the output function 
{
  cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\n\n";
}
// Declare a common derived class Graduate
class Graduate:public Student
{
public:
  Graduate(int, string, float, float);// Declaration constructor 
  void display( );// Declare output function 
private:float pay;
};
// Graduate Class member function implementation 
void Graduate::display( )// Define the output function 
{
  cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\npay="<<pay<<endl;
}
Graduate::Graduate(int n, string nam,float s,float p):Student(n,nam,s),pay(p){}
// The main function 
int main()
{
  Student stud1(1001,"Li",87.5);// define Student Class object stud1
  Graduate grad1(2001,"Wang",98.5,563.5);// define Graduate Class object grad1
  Student *pt=&stud1;// Defines a pointer to a base class object pt
  pt->display( );
  pt=&grad1;
  pt->display( );
  return 0;
}

The result is as follows:


num:1001(stud1 The data of )
name:Li
score:87.5

num:2001 (grad1 Data in the base class section )
name:wang
score:98.5

If you want to print out all the data members of grad1, you can, of course, call the display function by object name, such as grad1.display (), or define a pointer to ptr to Graduate class objects, ptr to gradl, and ptr-> display () call. This is certainly possible, but if the base class has more than one derived class, each derived class produces a new derived class, forming a family of classes from the same base class. Each derived class has a function of the same name, display, in the program to call a different class of the same name in the same family of functions, to define more than one pointer to each derived class variable. Neither approach is convenient; it requires different ways of calling functions of the same name for different derived classes, and, as mentioned earlier, takes the specified buses to different destinations, one to one, without error. It would be nice to be able to call all the functions of the same name of different classes in the same family in the same way.

You can solve this problem with virtual functions. The following is a slight change to the program. When declaring the display function in the Student class, add the keyword virtual (
) on the far left


  virtual void display( );


This declares the display function of the Student class as virtual. The rest of the program is unchanged. To recompile and run the program, note the analysis results:


num:1001(stud1 The data of )
name:Li
score:87.5

num:2001 (grad1 Data in the base class section )
name:wang
score:98.5
pay=1200 ( This term didn't exist before )

Look! That's the magic of virtual functions. Now with the same pointer variable (pointer to the base class object), not only output all the data of students stud1, but also output all the data of graduate students grad1, indicating that display function of grad1 has been called. Use the same call form "pt-> display() ", and pt is a pointer to the same base class that can call virtual functions of different classes in the same family. This is called polymorphism, where different objects respond differently to the same message.

The original base class pointer is used to point to the base class object, if it points to the derived class object, then the pointer type conversion, the derived class object pointer first converted to the base class pointer, so the base class pointer points to the derived class object in the base class part. You cannot call a member function in a derived class object through a base class pointer until the program is modified. Virtual functions break through this limitation by replacing the original virtual function of the base class with the virtual function of the derived class in the base class part of the derived class, so the virtual function of the derived class is called when the base class pointer points to the derived class object. Note that this only works if you declare a virtual function with virtual. If you do not declare a virtual function, you cannot attempt to call a non-virtual function of a derived class through a base class pointer.

The above functions of virtual functions are very practical. In object-oriented programming, class inheritance is often used to preserve the characteristics of the base class and reduce the development time of new classes. However, some member functions inherited from the base class do not fully meet the needs of the derived class. For example, the display function of the base class outputs only the data of the base class, while the display function of the derived class outputs the data of the derived class. In the past, we have made the output functions of derived classes have different names than the output functions of base classes (display and display1, for example), but it is inconvenient to have many different function names if you have many levels of derivation. If a function with the same name is used, an override of the same name will occur.

Using virtual functions solves this problem nicely. As you can see, when a member function of a base class is declared virtual, it is allowed to be redefined in its derived class, given new functions, and called by a pointer to the base class to an object of a different class in the same family. Dynamic polymorphism implemented by virtual functions is when objects of different classes in the same family respond differently to the same function call.

Virtual functions are used as
Declare the member function virtual in the base class with virtual.
This allows you to redefine the function in a derived class, give it new functionality, and make it easy to call. When defining a virtual function outside a class, you do not need to add virtual.
Redefine this function in a derived class, requiring that the function name, function type, number of function arguments, and type are all the same as the virtual function of the base class, and redefine the function body according to the needs of the derived class.
C++ states that when a member function is declared virtual, functions of the same name in its derived class automatically become virtual. Therefore, when the derived class redeclares the virtual function, you can add virtual or not, but it is customary to add virtual at each level of the function declaration to make the program clearer. If the virtual function of the base class is not redefined in the derived class, the derived class simply inherits the virtual function of its immediate base class.
Defines a pointer to a base class object and points it to the object in the same class family that needs to call the function.
This virtual function is called through the pointer variable, which is the function of the same name of the object to which the pointer variable points.
By using virtual functions in conjunction with pointer variables to base class objects, it is convenient to call functions of the same name of different classes in the same class family, as long as the base class pointer to point. If the pointer keeps pointing to objects of different classes in the same class, the function of the same name in those objects can be called repeatedly. This is like the previous saying, constantly tell the taxi driver where to go, and then the driver will take you to where you want to go.

Need to be explained; Sometimes non-virtual functions defined in the base class are redefined in the derived class (such as the area function in the example). If the member function is called with the base class pointer, the system calls the member function in the base class part of the object. If the member function is called with a derived class pointer, the system calls a member function in a derived class object. This is not a polymorphism (different types of Pointers are used) and does not use the functionality of virtual functions.

The function overloading described previously deals with functions of the same name at the same level, while virtual functions deal with functions of the same name at different derived levels. But unlike an overload, where the head of a virtual function is the same for the same family of functions, the head of a function is different (the number of arguments or the type of arguments) when the function is overloaded.

When should declare the virtual function
There are two things to note when using virtual functions:
You can only declare a member function of a class as a virtual function with virtual, and you cannot declare an ordinary function outside the class as a virtual function. Because virtual functions allow you to redefine the virtual functions of a base class in a derived class. Obviously, it can only be used in the inheritance hierarchy of a class.
After a member function is declared virtual, a class in the same family of classes cannot define a function of the same name that is not virtual but has the same arguments (including number and type) and return value type as the virtual function.

On what grounds do you consider declaring a member function virtual? Consider the following:
The first step is to see if the class in which the member function resides will act as the base class. Then you can see that the member function cannot be changed after the class is inherited. If you want to change its function, you should generally declare it as a virtual function.
Do not declare a member function virtual if it is not modified after the class is inherited, or if it is not used by a derived class. Don't declare all the member functions in a class as virtual just because you want to be a base class.
Whether a call to a member function is accessed by an object name or by a base class pointer or reference should be considered. If it is accessed by a base class pointer or reference, it should be declared virtual.
Sometimes, when defining a virtual function, the body of the function is not defined, that is, the body of the function is empty. All it does is define a virtual function name, which is left to the derived class to add.

It should be noted that with virtual functions, the system must have some space overhead. When a class has virtual functions, the compiler constructs a virtual function table (virtual function table, vtable for short) for that class, which is an array of Pointers to the entry address of each virtual function. The time cost of dynamic association is small, so polymorphism is efficient.


Related articles: