The magical utility of C++ virtual functions

The magical utility of C++ virtual functions

0X00 Foreword

Maybe most people started to learn C++ just like me. For the word "virtual", it feels a little bit incomprehensible and foggy.

Today we will clarify this virtual function

0X10 What is a virtual function?

In fact, virtual functions are not so false and empty definitions, just one sentence:

In the class definition of the function, if the qualifier vitualmodified virtual function is

How about it, is it simple and neat without ink

But let’s be a little more realistic, just go to the code

We first define a class, the class name isAnimal, Use it as a base class

class Animal
{
    
    
	public:
	Animal(){
    
    cout<<"I'm an animal!"<<endl;}

	void sleep(){
    
    cout<<"I'm sleep"<<endl;}
	virtual eat(){
    
    cout<<"I'm eating"<<endl;}

	virtual ~Animal(){
    
    cout<<"Remember me,I'm an animal! Bye!"<<endl;}
}

As can be seen from the above class method, a constructor is defined, an ordinary member function sleep(), a virtual function eat(), and a destructor. As for why the destructor is also a virtual function, this will have to wait until later Announced.

Now everyone just needs to take a good look at our virtual function and remember what it looks like

What is the use of 0X20 virtual functions?

Now that we have recognized virtual functions, someone will ask: What is the use of playing it like this?

Don't worry, there is one more thing we need to do to make this clear.

Since there is a base class, should there be a derived class? That's right

Below we also need to create a new derived classDog, It inherits our previousAnimalclass

class Dog:public Animal
{
    
    
   public:
      Dog(){
    
    cout<<"I'm a dog"<<endl;}
      
      void sleep(){
    
    cout<<"I'm a dog and I'm sleep"<<endl;}
      virtual void eat(){
    
    cout<<"I'm eating bones"<<endl;}

      virtual ~Dog(){
    
    cout<<"Remember me,I'm a dog! Bye!"<<endl;}
}

Well, after the inheritance is complete, you can see that there is a Dog constructor, and the Animal functions sleep() and eat() are rewritten, as well as the following destructor

Once the Dog class is written, we need to talk about Virtual function What is the role of

First of all, we know (by default we know 233) that the pointer of the base class points to the derived class, and the reference of the base class can refer to the object of the derived class

So I can have the following code:

Animal animal;
Dog dog;
Animal * fa1=&base;
Animal * fa2=&dog;

The above code defines an Animal class object animal, and a Dog class object dog.
And define two base class pointers fa1, fa2 respectively point to animal and dog

Now we call the method of the object through the pointer:

cout<<"animal:"<<endl;
fa1->sleep();
fal->eat();
cout<<"dog:"<<endl;
fa2->sleep();
fa2->eat();

Call the method of two objects through two pointers, so what is the result?
Insert picture description here
Isn't it strange?

Obviously the two functions have been rewritten, why is fa2 called Animal::sleep()instead ofDog::sleep()

The reason is simple: one is a virtual function and the other is not!

That's right, this is the function of virtual functions:

When the pointer (or reference) to the derived class calls the class function, for the virtual function, the virtual function of the derived class will be called, and the general member function will only call the function of the base class

It may sound a bit convoluted at first, but through the above example, everyone should be clear.

What is the use of 0X30 virtual functions?

But after reading the above explanation, some students should ask again, and they understand, but it feels useless. It seems a bit tasteless.

You are wrong to think so

1. For polymorphism
In fact, in C++, many things are designed for polymorphism.

So what kind of polymorphism is this virtual function for?

Okay, let's add a function to design, in which the action of "animal" needs to be called. Of course the animals here include oursAnimal also includeDog. In other words, we need to pass a class reference to the function

Now suppose that we have never had a virtual function (or we want to call the sleep function now).
How should our function be designed?
I think it should be like this:

void action(Animal &animal)
{
    
    
 //.....
 animal.sleep();
 //....
}

void action(Dog &dog)
{
    
    
 //.....
 dog.sleep();
 //....
}

We assume that the omitted things are the same, that would be more troublesome, right?

Just one sentence is different and you need to write a function, which wastes space and time.

What if we now have virtual functions? (That is, call the eat function)

Only one function is needed at this time

void action(Animal &fa)
{
    
    
 //.....
 fa.sleep();
 //....
}

why?
Since the base class reference can refer to both the base class and the derived class, it is possible to pass in whether it is a base class object or a derived class object.
And as I said earlier, for virtual functions, if it is a base class reference, it calls the base class method. If it is a derived class reference, then call the derived class method
. This is much better than when there is no virtual function. What-polymorphism!

2. In order to avoid memory leaks,
etc., what are you talking about, is there a memory leak?

If you have any doubts, you are right, this is the most error-prone place!

Let's go back to the front, is there a hole left unfilled? Yes, why the destructor is also used virtualto modify?

We know (again forcefully know (dog head)), the destructor is generally used to release the heap space previously requested. Although I don't have it here, in general the destructor is used to do this. I now use cout to distinguish two classes

We now execute the following function, but this time we will not virtualmodify the destructor

Animal* fa=new Dog();
//...
delete fa;

This time we use the Animal pointer to new a Dog object, and then delete it after performing a series of operations

The final execution result is as follows: I
Insert picture description here
found that only this sentence appeared, which means that only the destructor of Animal was called

Then the problem is serious. What I defined is a Dog object. If I apply for a large amount of heap memory in Dog, it will not be released. What is this-memory leak!

How to solve it? ——Virtual function

Let’s set the destructor to a virtual function and run it again.
Insert picture description here
Now we are comfortable, and Dog’s destructor is also called, so we don’t have to worry about memory leaks.

The reason is simple, because it is a virtual function, so the destructor of the derived class is called at this time, and then the destructor of the base class is called instead of just the base class.

0X40 virtual function summary

There are several key points:

  • Using keywords in the base class method declaration virtualcan make the method virtual in the base class and all derived classes (including classes derived from derived classes) (that is, in fact, the virtual function used in our derived class In fact, it is not necessary to write virtual, because it will automatically become a virtual function, but we are still used to write it to distinguish)
  • If you use a reference or pointer to an object to call a virtual function, the program will use the method defined by the object type instead of the method defined for the reference or pointer type. This is called dynamic binding. This behavior is very important, because the base class pointer or reference can point to the derived class object
  • If the defined class will be used as the base class, then those class methods that are to be redefined in the derived class should be defined as virtual

There are several points to note:
1. Constructor The
constructor cannot be a virtual function, because the calling sequence of the constructor is not used for the inheritance mechanism. The derived class does not inherit the constructor of the base class, so it does not make any sense to define the constructor as a virtual function

2. Destructor The
destructor should be a virtual function. The reason has just been discussed, in order to avoid memory leaks

3. Friend functions
Friend functions cannot be virtual functions, because friend functions are not class members, only class members can be virtual functions

4. No redefinition
If the derived class does not redefine the function, the base class version of the function will be used

0X50 Afterword

That's it for the content of virtual functions. As long as everyone can understand its role and the designer's original intention, it should be easy to remember and use with heart.

Finally, I wish you all progress every day and study hard~

See you next time!

———————————————————————————————————————————————— ————
Reference: "C++ primer plus 6th edition"

Guess you like

Origin blog.csdn.net/rjszz1314/article/details/104580853