[C ++ in-depth analysis] 34. Polymorphism and virtual functions

1 Review of function rewriting

  • The overridden function in the parent class will still inherit to the child class
  • Functions overridden in subclasses will override functions in parent classes
  • You can access the functions in the parent class through the scope distinguisher (: :)

In the previous blog, we know that when a pointer (reference) of a parent class is used to point to a child class object, the child class object degenerates into a parent class object, and only members of the parent class can be accessed. In other words, regardless of whether the pointer of the parent class points to the object of the parent class or the object of the child class, the function of the parent class is called.

2 Polymorphic concepts

We want to call the rewrite function according to the actual type of the object pointed to. When the pointer (reference) points to the parent class object, call the member function in the parent class, and when it points to the subclass object, call the rewritten function in the subclass. This is polymorphism.

The concept of polymorphism in object-oriented:

  • Determine the specific target of the function call according to the actual object type
  • The same call statement has many different manifestations in actual operation

Insert picture description here

In C ++, the virtual keyword is used to implement polymorphism, and the functions modified by virtual are called virtual functions.

Programming experiment: polymorphic first experience

// 34-1.cpp
#include<iostream>
using namespace std;
class Parent
{
public:
    virtual void print()					// 这里必须要 virtual
    {
        cout << "I am Parent" << endl;
    }
};
class Child : public Parent
{
public:
    void print()						// 这里的 virtual 可以省略
    {
        cout << "I am Child" << endl;
    }
};
void how_to_print(Parent* p)
{
    p->print();
}
int main()
{
    Parent p;
    Child c;
    how_to_print(&p);
    how_to_print(&c);
    return 0;
}

Parent class Parent and child class both have member function void print (), access the member function of the class through the function void how_to_print (Parent * p), which is equivalent to the pointer of the parent class pointing to the object of the child class or the object of the parent class, if there is no Defined as a virtual function, all the functions of the parent class are called. The member function is defined as a virtual function, and the member function of the corresponding class can be dynamically called according to the pointed object.

To achieve polymorphism, the functions of the parent class should be decorated with virtual, and the subclasses can be written or not written. Therefore, line 7 requires virtual modification, and the member function print () on line 15 can be modified with virtual or can be omitted.

Compile and run

$ g++ 34-1.cpp -o 34-1
$ ./34-1
I am Parent
I am Child

Use polymorphism to dynamically call subclass member functions based on the object pointed to by the parent class pointer, and call parent class member functions when pointed to the parent class object. Function rewriting must be polymorphic, otherwise it is meaningless.

2.1 Static linking and dynamic linking

Static binding: specific function calls can be determined during program compilation, such as function overloading.
Dynamic binding: specific function calls can be determined only after the program is actually running, such as function rewriting.

// 34-2.cpp
#include<iostream>
using namespace std;
class Parent
{
public:
    virtual void func()
    {
        cout << "void func()" << endl;
    }
    virtual void func(int i)
    {
        cout << "void func(int i) : " << i << endl;
    }
    virtual void func(int i, int j)
    {
        cout << "void func(int i, int j) : (" << i << ", " << j << ")" << endl;
    }
};
class Child : public Parent
{
public:
    void func(int i, int j)
    {
        cout << "void func(int i, int j) : " << i + j << endl;
    }
    void func(int i, int j, int k)
    {
        cout << "void func(int i, int j, int k) : " << i + j + k << endl;
    }
};
void run(Parent* p)
{
    p->func(1, 2);
}
int main()
{
    Parent p;
    p.func();
    p.func(1);
    p.func(1, 2);
    cout << endl;

    Child c;
    c.func(1, 2);
    cout << endl;

    run(&p);
    run(&c);
    return 0;
}
  • The member functions virtual void func (), virtual void func (int i) and virtual void func (int i, int j) in the parent class are overloaded.
  • The member functions void func (int i, int j) and void func (int i, int j, int k) in the subclass are also overloaded.
  • The virtual void func (int i, int j) in the parent class and the void func (int i, int j) in the child class form a dynamic link, the parent class points to the object, and is dynamically called according to the object type
  • The function func with the same name as the parent class defined in the subclass, with the same name hidden, cannot be accessed directly, and the subclass object wants to access the parent class members using the scope distinguisher (: :)

Compile and run

$ g++ 34-2.cpp -o 34-2
$ ./34-2
void func()
void func(int i) : 1
void func(int i, int j) : (1, 2)

void func(int i, int j) : 3

void func(int i, int j) : (1, 2)
void func(int i, int j) : 3

3 Summary

1. Modification of member functions by virtual keyword to achieve polymorphism
2. Distinguish between static and dynamic binding

Published 298 original articles · praised 181 · 100,000+ views

Guess you like

Origin blog.csdn.net/happyjacob/article/details/104367778