C++ polymorphism (virtual function, static link, dynamic link, virtual function table, virtual table pointer)

Today, I took a look at the polymorphism of C++ and found that it has not been clear.

What is polymorphism

Polymorphism literally means multiple states, which will appear in inherited classes. Let's look at an example:

Static polymorphism

#include<iostream>
using namespace std;

class A {
    
    
public:
    A():i(10){
    
    }
    void f() {
    
     cout<< "A::f()"<<i<<endl;}
    int i;
};

class B : public A{
    
    
public:
    B():j(20) {
    
    }
    void f()  {
    
     cout << "B::f()" << j <<endl;}
    int j;
};

class C : public A{
    
    
public:
    C():q(30) {
    
    }
    void f()  {
    
     cout << "C::f()" << q <<endl;}
    int q;
};

int main()
{
    
    
	A a;
	B b;
	C c;
	A *p = &b;
	A *q = &c;
	p->f();
	q->f();
	return 0;
}

What will the program output in this case?
We will find that the results are all A::f()10;
this is because it has been determined at compile time that the function of the base class, which is A, is used as the output function, so using the base class pointer to point to the subclass object will still call the function of the base class, this is Static linking is also called static polymorphism .
Look at the next example:

Dynamic polymorphism

Still the same program, we add virtual to the f function of the base class and define it as a virtual function.

#include<iostream>
using namespace std;

class A {
    
    
public:
    A():i(10){
    
    }
    virtual void f() {
    
     cout<< "A::f()"<<i<<endl;}
    int i;
};

class B : public A{
    
    
public:
    B():j(20) {
    
    }
    void f()  {
    
     cout << "B::f()" << j <<endl;}
    int j;
};

class C : public A{
    
    
public:
    C():q(30) {
    
    }
    void f()  {
    
     cout << "C::f()" << q <<endl;}
    int q;
};

int main()
{
    
    
	A a;
	B b;
	C c;
	A *p = &b;
	A *q = &c;
	p->f();
	q->f();
	return 0;
}

The results of the operation are:

B::f()20
C::f()30

At this time, the pointer points to the function of the subclass. This is the dynamic binding in polymorphism , also called dynamic polymorphism .

Virtual function

I wrote that after using virtual functions, dynamic polymorphism is realized. Next, let's analyze what happens in the memory.
If we output a normal class size, for example:

class A{
    
    
	A(){
    
    }
	void print(){
    
    cout<<"1"<<endl;}
}
int main(){
    
    
	cout<<sizeof(A)<<endl;
}

Then turn the print function into a virtual function and output its size:

class A{
    
    
	A(){
    
    }
	virtual void print(){
    
    cout<<"1"<<endl;}
}
int main(){
    
    
	cout<<sizeof(A)<<endl;
}

We will find that the class of virtual functions is a bit larger than the class of ordinary functions. Why?
Because every object of a class with virtual functions will be preceded by a pointer to a table that stores virtual functions, we call it a vtable, and this table is shared by all objects.

vtable

As mentioned above, in order to achieve polymorphism, C++ uses a dynamic binding method. The core of this method is the vtable (virtual function table). Each class with virtual functions has a virtual function table. All objects of this class share a virtual function table. The virtual function table is actually an array of pointers to virtual functions.

For example, the following code:

class A {
    
    
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};

Its virtual table is as follows:

Virtual table pointer

Because the virtual function table belongs to the class, all objects share a virtual function table. How does each object know which virtual function table is? * Each object points to its virtual function table through a virtual table pointer __vptr.
Insert picture description here

Dynamic binding

Here is an example to see how C++ uses virtual function tables and virtual table pointers to achieve dynamic binding.

class A {
    
    
public:
    virtual void vfunc1();
    virtual void vfunc2();
    void func1();
    void func2();
private:
    int m_data1, m_data2;
};

class B : public A {
    
    
public:
    virtual void vfunc1();
    void func1();
private:
    int m_data3;
};

class C: public B {
    
    
public:
    virtual void vfunc2();
    void func2();
private:
    int m_data1, m_data4;
};

According to the inheritance relationship, the following results can be obtained:
Insert picture description here

Virtual function and pure virtual function

class A{
    
    
	virtual void A(){
    
    cout<<"A"<<endl;}
	virtual void B()=0; 
}

The above is an example of the coexistence of virtual functions and pure virtual functions. The difference between them is that the virtual function provides the implementation of the function, so the subclass can choose to override or directly inherit this function, while the pure virtual function requires the subclass to implement this function.

Abstract class

A class with pure virtual functions is an abstract class, and an abstract class is equivalent to the definition of a code of conduct and can only be used as a base class. For example, if we hope that the subclass must complete some actions, we write these actions as pure virtual functions.
It should be noted that those that inherit abstract classes but do not implement pure virtual functions are still abstract classes.

The shoulders of giants:
1. About virtual function tables and virtual function pointers

Guess you like

Origin blog.csdn.net/weixin_45146520/article/details/109537291