Simple c++ polymorphism explanation


foreword

Polymorphism is further divided into static polymorphism and dynamic polymorphism:
(1) Static polymorphism: Function overloading and function template instantiate multiple functions (essentially function overloading), that is, static polymorphism is also called polymorphism during compilation. state.

(2) Dynamic polymorphism, also known as dynamic binding or late binding (late binding): runtime polymorphism can be achieved through virtual functions.
此文章只进行动态多态的讲解


1. What is polymorphism?

To put it simply, polymorphism is a variety of forms of function calls. Using polymorphism can make different objects produce different actions and results when they accomplish the same thing.

多态的产生必须具备两个条件:

  1. A virtual function must be called through a base class pointer or reference.

  2. The called function must be a virtual function, and the derived class must override the virtual function of the base class.


Two, give an example

class A {
    
    
public:
    A() {
    
    }
   virtual void print(int num) {
    
    
        cout << "num:---" << num<< endl;
    }
}

class B :public A{
    
    
public:
    B(int cb) :n_(cb) {
    
    }
     void print(int num) {
    
    
        int re = num * n_;
        cout << "num:+++++++" << re << endl;
    }
private:
    int n_;
};
int main(){
    
    
   
    A *temp = new B(2);
    temp->print(3);
    delete temp;
    return 0;  
}

The subclass B inherits the base class A, and rewrites the virtual function print in the base class A; in the main function, the pointer of A points to the object of B, which satisfies the condition of polymorphism. So the printed result should be the result printed by the print function in B.

insert image description here


3. Virtual function table

Why polymorphism occurs, the reason comes from the virtual function table .
First, let's take a look at the internal structure of classA

class A {
    
    
public:
    A() {
    
    }
   virtual void print(int num) {
    
    
        cout << "num:---" << num<< endl;
    }
}

We know that the size of an empty class in memory is 1, so if the virtual modification is removed, the size of A is actually 1. Here we can verify it through the Developer Command Prompt that comes with VS.
insert image description here
But if the virtual modification is added again, the size of A becomes 4, and there is one more vftable.
insert image description here
This is because, when virtual is added before a non-static member function of a class , the class will generate a pointer vfptr (virtual function pointer), that is, a virtual function pointer (4 bytes) to point to a vftable (virtual function table) virtual Function table , the address &A::print of the member function is saved in the virtual function table.
So what will happen if the subclass B inherits the base class A? We also use the Developer Command Prompt to check it out.

First of all, we only inherit and do not rewrite the virtual functions of the base class.

class B :public A{
    
    
public:
    B(int cb) :n_(cb) {
    
    }
    //virtual void print(int num) {
    
    
    //    int re = num * n_;
    //    cout << "num:+++++++" << re << endl;
    //}
private:
    int n_;
};

insert image description here
At this time, we noticed that the size of B is 8, that is, the inherited virtual function pointer of A, and B’s own int n_, but at this time the address stored in the virtual function table in B is the inherited &A::print .

Then we rewrite the base class virtual function function

class B :public A{
    
    
public:
    B(int cb) :n_(cb) {
    
    }
    virtual void print(int num) {
    
    
        int re = num * n_;
        cout << "num:+++++++" << re << endl;
    }
private:
    int n_;
};

insert image description here
At this point we find that &A::print in the virtual function table in B is overwritten as &B::print.

When the polymorphic conditions are satisfied, when the pointer or reference of the parent class calls the virtual function, it will find the corresponding virtual function call in the virtual table in the pointed object at runtime. The bottom layer of the reference is also implemented by the pointer, and the parent class points to Slicing occurs when subclassing. Therefore, the pointer points to the object of the parent class, and the virtual function of the parent class is called, and the pointer points to the object of the subclass, and the virtual function of the subclass is called.

Four, some little knowledge

When inheriting, the virtual function of the subclass can also be rewritten without adding the virtual keyword, because the virtual function of the base class is inherited after inheritance, and the virtual function attribute is still maintained in the derived class. But it is not recommended to write this way, because subclasses may also be inherited, so we will write it honestly when rewriting.

Virtual functions require the same return value type, the same function name, and the same parameter list , but covariance is an exception. When a subclass rewrites a base class virtual function, the return value type of the base class virtual function can be different. But the return value type must also satisfy the parent-child relationship.

Summarize

It is my first time to write an article, so it is inevitable that there are omissions. If you think it is useful, then you think it is useful. If you think my writing is not good, I will change it when I see it. Thank you guys.

Guess you like

Origin blog.csdn.net/Done_for_me/article/details/129681648