In depth understanding of polymorphism in C++

  • 2020-04-01 23:38:24
  • OfStack

C++ programming language is a wide range of applications, support a variety of programming computer programming language. We will introduce some basic knowledge of C++ polymorphism in detail for you today, so that you can have a full grasp of it in the learning process.

Polymorphism, which can be summarized simply as "one interface, many methods," is a core concept in the object-oriented programming world. Polymorphic (" isn "), which literally means many shapes.

C++ polymorphism is implemented through virtual functions that allow subclasses to redefine member functions, and subclasses to redefine parent classes in a way that is called override, or override. (I think to add here, rewriting the words can have two kinds, direct rewriting a member function and rewrite the virtual functions, only override the virtual function can be classified as embodies the c + + polymorphism) and overloading is allowed to have more of the same name function, and the function's parameter list, allowing different number of parameters, parameter types are different, or both. The compiler modifies the name of the function with the same name according to the different list of these functions, thus generating some preprocessing functions with different names to realize the overload problem when the function with the same name is called. But this does not reflect polymorphism.

The essential difference between polymorphism and non-polymorphism is whether the function address is bound early or late. If the function is called, the function's call address can be determined and the code produced during compiler compilation, and is static, that is, the address is early bound. If the address of the function call cannot be determined during the compiler and needs to be determined at runtime, this is late binding.

So what does polymorphism do? Encapsulation makes code modular, and inheritance extends existing code, all for code reuse. The purpose of polymorphism is for interface reuse. That is, regardless of which class object is passed, the function can call the implementation method that ADAPTS to the respective object through the same interface.

The most common use is to declare a pointer to a base class, which points to any subclass object, calls the corresponding virtual function, and implements different methods according to the subclass. If virtual functions are not used, that is, without the C++ polymorphism, the calls to the corresponding function with the base class pointer will always be restricted to the base class function itself, and cannot be called to the overridden function in the subclass. Because there is no polymorphism, the address of the function call will be fixed, and the fixed address will always be called to the same function, which makes it impossible to achieve the purpose of one interface and multiple methods.

Written test topic:


#include<iostream>
using namespace std;
class A
{
public:
 void foo()
 {
 printf("1n");
 }
 virtual void fun()
 {
 printf("2n");
 }
};
class B : public A
{
public:
 void foo()
 {
 printf("3n");
 }
 void fun()
 {
 printf("4n");
 }
};
int main(void)
{
 A a;
 B b;
 A *p = &a;
 p->foo();
 p->fun();
 p = &b;
 p->foo();
 p->fun();
 return 0;
}

P - the first > Foo () and p - > Fuu () is easy to understand, itself is a pointer to the base class, pointing to the base class object, call the functions of the base class itself, so the output is 1, 2.

The second output is 1, 4. P - > Foo () and p - > Fuu () is the base class pointer to the subclass object, which formally reflects the use of polymorphism, p- > Since the pointer to foo() is a base class pointer, the point is a function with a fixed offset, so the only code that is pointed to is the foo() function of the base class, so the output is still 1. The p - > Fun () a pointer is a pointer to a base class, pointing to the fun is a virtual function, because each virtual function has a virtual function list, at this point p call fun () is not directly call a function, but the virtual function through the list to find the address of the corresponding function, therefore, according to point to objects of different function addresses will also be different, it will find the corresponding subclass of fun () function's address, so that the output result will be the result of the subclass 4.

There is an alternative to the written test. namely

B * PTR = (B *)&a;   PTR - > Foo ();   PTR - > Fun ();

Ask the output of the two calls. This is a base class object that USES the subclass's pointer to point to a cast to the subclass's address. As a result, the output of these two calls is 3,2.
I don't quite understand this usage. In principle, since B is a subclass pointer, it is given the address of the base class object, but PTR - > When foo() is called, the offset is the offset of the subclass object because the address offset is fixed, so the subclass function is called even if it points to a base class object, although there may be no instantiation of the subclass object from beginning to end.
The PTR - > The call to fun(), again probably due to the C++ polymorphism, points to a base class object, finds the address of the fun() function in the base class through a reference to the list of virtual functions, and therefore calls the function of the base class. This shows the power of polymorphism, can adapt to a variety of changes, whether the pointer is the base class or subclass, can find the correct implementation method.


//Summary: 1. Polymorphism can only occur with virtual
//2, no polymorphic (no virtual) call on the original type
#include<iostream>
using namespace std;
class Base
{
public:
 virtual void f(float x)
 {
 cout<<"Base::f(float)"<< x <<endl;
 }
 void g(float x)
 {
 cout<<"Base::g(float)"<< x <<endl;
 }
 void h(float x)
 {
 cout<<"Base::h(float)"<< x <<endl;
 }
};
class Derived : public Base
{
public:
 virtual void f(float x)
 {
 cout<<"Derived::f(float)"<< x <<endl;  //Polymorphism, coverage
 }
 void g(int x)
 {
 cout<<"Derived::g(int)"<< x <<endl;   //hidden
 }
 void h(float x)
 {
 cout<<"Derived::h(float)"<< x <<endl;  //hidden
 }
};
int main(void)
{
 Derived d;
 Base *pb = &d;
 Derived *pd = &d;
 // Good : behavior depends solely on type of the object
 pb->f(3.14f);  // Derived::f(float) 3.14
 pd->f(3.14f);  // Derived::f(float) 3.14
 // Bad : behavior depends on type of the pointer
 pb->g(3.14f);  // Base::g(float) 3.14
 pd->g(3.14f);  // Derived::g(int) 3 
 // Bad : behavior depends on type of the pointer
 pb->h(3.14f);  // Base::h(float) 3.14
 pd->h(3.14f);  // Derived::h(float) 3.14
 return 0;
}

Confusing hiding rules

It wasn't difficult to distinguish between overloading and overwriting, but C++ 's hidden rules dramatically increase the complexity of the problem.
Here, "hidden" means that the functions of derived classes mask the functions of the base class with the same name. The rule is as follows:
(1) if the function of the derived class is the same as the function of the base class, but the parameters are different. In this case, virtual or not
Keyword, the function of the base class will be hidden (be careful not to be confused with overloading).
(2) if the function of the derived class is the same as the function of the base class, and the parameters are the same, but the base class function is not virtual
The keyword. At this point, the functions of the base class are hidden (be careful not to be confused with overrides).
In the above program:
(1) the function Derived::f(float) overrides Base::f(float).
(2) the function Derived::g(int) hides Base::g(float) instead of overloading.
(3) the function Derived::h(float) hides Base::h(float) instead of overwriting.

C++ pure virtual functions

A, definitions,
A pure virtual function is a virtual function declared in a base class, which is not defined in the base class, but requires any derived class to define its own implementation. The way to implement a pure virtual function in a base class is to add "=0" after the function prototype.
Virtual void funtion () = 0
Two, introduce the reason
1. To facilitate the use of polymorphism, we often need to define virtual functions in the base class.
2. In many cases, it is unreasonable for the base class itself to generate objects. For example, animals as a base class can be derived from tigers, peacocks, and so on, but the animals themselves generate objects that are clearly irrational.
To solve the above problems, the concept of pure virtual Function is introduced, and the Function is defined as pure virtual Function(method: virtual ReturnType Function()= 0;). , the compiler requires that it be overridden in a derived class to achieve polymorphism. Classes that also contain pure virtual functions are called abstract classes and cannot generate objects. This is a good solution to the above two problems.
Third, the concept of similarity
1. Polymorphism
When the same object receives different messages or different objects receive the same message, different implementation actions are generated. C++ supports two types of polymorphism: compile-time polymorphism and run-time polymorphism.
A. Compile-time polymorphism: through overloaded functions
B. runtime polymorphism: through virtual functions.
2. Virtual functions
A virtual function is a member function declared as virtual in a base class and redefined in a derived class, which implements dynamic Override of a member function (Override)
3. Abstract class
Classes that contain pure virtual functions are called abstract classes. Because an abstract class contains undefined pure virtual functions, an object of an abstract class cannot be defined.


Related articles: