Is the polymorphism function overloaded or overwritten

Virtual functions and polymorphism

The concept of polymorphism

C ++ offers a complete solution for these types of occasions that require greater coding flexibilityPolymorphism
Polymorphism refers toOne interface, multiple implementations
offers programmers the flexibility to control complex programs
In C ++ it has polymorphismStaticWithdynamicThere are two differences, all of which are achieved by function overload.
1. Static polymorphism
The implementation of the static polymorphism occurs at compile time. A typical example is general function overload (including operator function overload).

These statements fully embody a principle of polymorphism:One interface (name), multiple implementations
Static polymorphism can also be reflected in the inheritance tree. Consider the different shape classes we designed in the previous chapter. If there are object definitions:

Tiger inherits the what () member of its base class Felid (i.e. it has two members with exactly the same prototype), but in the above context the compiler processes member function calls when t.what (), searches directly for the name in the scope of the tiger, and when successfully found, it definitely calls the member function of the tiger class itself instead of calling the homonymous function of the base class.
inCompile timeThe determined polymorphism is referred to as "static polymorphism (early matching)".

2. Dynamic polymorphism
Static polymorphism can give the program design some degree of flexibility, but only covers the polymorphism in the compilation phase and requires more flexibility, e.g.Runtime polymorphismBut nothing can be done.
In C ++ the dynamic polymorphism is dependentVirtual function(virtual function)

The cornerstone of the virtual polymorphism function

The concept and properties of virtual functions

A pointer (or reference) to the base class can be used to refer to an object derived from the base class
When there are multiple or multilayered derived classes, the membership functions of all derived class objects can be accessed through a base class pointer (or reference) so that an interface and multiple implementations can be implemented
designed square class and its derived classes when you want to make member function calls like quad-> area ().replaceFunction of the same name in the base class
Method: Make the scope () of the derived classHome page(overwrite) the function of the same name of the base class

1. The concept of virtual functions
Used to create member functions of derived classesHome pageThe member of the base class with the same name, then the member function of the base class must be described asVirtual functionThe syntax is as follows:

The keyword virtual tells the compiler clearly: The member function of the same name in the derived class of this class overwrites the function defined in the base class

A virtual function is declared or itsThe ancestral class containsThe class with virtual functions is called "Polymorphic class(polymorphic class) ”。
Once a member function of the base class has been declared virtual, we say that the function "Virtual properties". Virtual properties have such properties:
① The virtual characteristics must be assigned to the classMembership function
② Virtual functionCannot be a global function,and alsoCannot be a static member function of the class
Friends cannot be declared as virtual functionsBut virtual functions can be friends of a different class;
④ The virtual properties can be inherited. If derived classThe prototype is consistentIf a virtual function of the base class is overloaded, the compiler regards it as a virtual function, even if the function is not explicitly specified as virtual in the derived class.
In the inheritance tree, every well-formed polymorphic class has oneFinal coverage function(final overrider)。
If not, the derived class inherits from its ancestor. However, this is not a good design, it is badly shaped.
There is one fact to be cleared up here. Although the members of the derived class cover the virtual members of the same name in the base class, this does not mean that the code of the child members replaces the code of the ancestor. Indeed, the virtual members of the ancestorsStill exists and is accessible,useName qualificationMay complete the visit of the ancestor of the same name. E.g.

But this visitCan only be in derived classesIn processing.

2. Use of virtual functions: Liskov substitution principle

This code works correctly, but the program code tries to understand the derived class through the facilities (pointers) of the base class, which violates the "Liskov Substitution Principle (LSP)" in the OOD design principle. The LSP principle can be briefly described as:When using base class pointers or references, derived class objects can completely replace the base class objects, and the program entity cannot recognize this substitution

If you want to use f () in your code, here's what you should do:
① Give f () in the derived classOverwrite version
② Define the pointer or reference Pr of ancestral class X;
③ Define the derived class object o and let pr point to it.
④ The virtual function is accessed in a similar way to pr-> f () or pr.f () instead of calling it via o.f ().

3. Inheritance of virtual properties
Virtual characteristics can be inherited. When a function in the base class is declared as virtual in the inheritance tree, all of its descendants are displayedSame prototypeThe functionEverything will be imaginaryof.
If a function is overloaded with another prototype in a derived class, how does that function affect virtual property inheritance?

It can be seen that the what (int) in the Tiger class differs from the function prototype of the same name in the base class, so it loses its virtual properties and we cannot use rt.what (0) to call it, which causes a compile-time error: In the bengalTiger class, the prototype consistently overloads the virtual function what () of the felt class, so that the virtual properties are still retained.

4. Virtual destructor
The class destructor can be described as a virtual function and should also be virtual. The constructor of a class cannot be a virtual function. (Thinking: why? Http://blog.sina.com.cn/s/blog_620882f401016ri2.html)


There are two ways to solve the problem:
• PassedForced type conversionConvert the pointer p toDerived class pointerThe specific method is as follows:
delete (tiger *) (ptr);
• Put the Felid classThe destructor is described as virtualof:
virtual ~ felid () {…}
Here we cannot use the dynamic_cast operator for downcasting, since the Felid defined in the example is not a polymorphic class, otherwise it will cause a compilation error.
Note that the destructor cannot be inherited, onlyVirtual propertiesBut it can be inherited.

Implementation mechanism of the virtual function

Thanks to the C ++ compiler, dynamic polymorphism can occur. The compiler does all of the work behind the scenes. When you create a polymorphic class, the compiler installs the necessary dynamic polymorphism mechanism for the class. What is the core of this mechanism?
The compiler must first create one for each class that contains virtual functionsVirtual table (VTABLE). In VTABLE the compilerPlace the virtual function address of the class. The compiler secretly sets in every class with virtual functionsA pointer(This is the additional data), called "virtual pointer (vpointer / VPTR)", points to the VTABLE of this object.
Set VTABLE for each class, initialize VPTR, add code for virtual function callsIt happens automaticallyYes, we don't have to worry about that. With the virtual function mechanism, the corresponding function of the derived class can be called, even if the compiler does not know the type of the object.

When does a member function have to be declared as a virtual function? Mainly consider the following points:
• First consider the class of the member functionIs it used as a base class?. Then look at the member function after class inheritanceWhether the function has been changed? in the event ofHope to changeIts function is generally declared as a virtual function
• If the member function works after the class is inheritedNo correction required, Or the function is not used in the derived class. Do not declare it as a virtual function

Overwrite operator and end operator

Pure virtual functions and abstract classes

• The introduction of purely virtual functions
• The base class often represents someabstractthe concept of. For example, Quadrilateral is a base class that represents a quadrilateral without a concrete shape, and other concrete body classes can be derived from Quadrilateral. In this inheritance tree, the base class Quadrangle embodies an abstract concept
• In this case, some virtual functions of the base class are usually undefined, but the derived class must redefine these virtual functions in order to make the derived class meaningful
The pure virtual function is a virtual function described in the base class that is not defined in the base class and is requiredEach derived class must define its own version
To illustrate a purely virtual function, the following general form is used:

In the construction and destructor of the class, ordinary member functions or even ordinary virtual elements can be called, but if they are directly or indirectlyPure virtual memberThen such behavior is unpredictable. So it shouldbreak up withSuch behavior.
If a classAt least one purely virtual function"Then call the class"Abstract class(abstract class) ”
Assuming that class A is an abstract class, its characteristics are:
Cannot create abstract class A object. The abstract class A can only be used as a base class for other classes. E.g.

If in a derived class of an abstract class the final coverage function of a pure virtual function is still a pure virtual function (ie a function body is not yet provided), thenThe derived class is still an abstract class

• Abstract classCannot be used as the parameter type and return type of a function. E.g.

Can declare pointers and references of abstract classes, they can be used as function parameters or return types. E.g.

• Abstract classCannot be used as an explicit conversionArt. E.g.

Question 1: Can the function body for the function be defined after declaring a pure virtual function in a class?
The answer is yes. E.g.

This approach has no grammatical problems, but it is almost meaningless: the Felid class is still an abstract class, and its derived classes must have an explicitly defined final override function of what (), otherwise the derived class Still abstract class. That is aBadly designed
Question 2: So is Felid still an abstract class?
Naturally

Question: If in the inheritance tree a derived class of a certain generation has completed all the coverage work (ie is no longer an abstract class), then do the descendants of this derived class not have to cover pure virtual functions?
The answer is yes. However, this is still a pathological design.

Class design: OOD principle

Principles of class organization
• Principle of individual responsibility
• Opening and closing principle
• Principle of reuse of combination / aggregation
• Richter substitution principle

1. Rely on the principle of inversion

However, if we expand the scope, for example: calculations can use other types of input devices (such as touchscreens etc.) and output devices (such as printers) etc. then because of this design these types cannot meet the needs of applicationsBad scalability
If we examine the design of the class, we can see that the implementation of the main class machine depends on itSpecificThis is the main cause of the restricted application. The way to solve the problem is to make the class independent of the specific device for which it is required to be usedabstract
Based on the abstract principle, we can redesign the class (interface) and its inheritance hierarchy:
• Design an abstract device to describe a uniform device interface
• Design the abstract class inputdev, a derived device class that is used to describe the unified input device interface. The keyboard class is a derived class from this class that implements the input interface
• Design the abstract class outputdev, a derived device class that is used to describe the unified output device interface. The monitor class is a derived class of this class that implements the output interface
• The class computer does not contain instances of specific device classes, but references to abstract devices. In this way, it doesn't depend on specific devices, but on abstraction

2. Principle of interface isolation
The faxPrinter is such an office device: it can be used as a printer or fax machine. Then, if we use classes / interfaces to simulate these concepts so that faxPrinter does the same thing as Printer and Faxm, we can consider this: Printer is an ancestor class, Faxm is a derived class, FaxPrinter is a derived class of Faxm .
There is a problem with designing the fax interface: if you want to design a class derived from Faxm (it's still just a fax machine), you need to implement interface printing (which is completely useless to you). Obviously, this is unreasonable. It can be said that the fax interface is "contaminated".
violates the "Interface Segregation Principle (ISP)":The client should not rely on interfaces that it does not needThe dependency of one class on another should be based on the smallest interface

3. The principle of least knowledge
Consider this problem: There are four types of devices that can communicate and exchange data with each other. If we use four classes to simulate the work of the device, the relationship between these classes can be as follows

When you add a new device class to the system, the association must be reconstructed to a certain extent, and the source code of the existing device class may need to be changed to adapt to the new device. Hence this designThe scalability is pretty badof
If any of the software modules (e.g. classes) are changed, you must do soInfluence other modules as little as possibleSo the extension will be relatively easy. For that you needThe breadth and depth of communication between software units must be limited. To summarize in one sentence:A software entity should interact with other entities as little as possible. This is that "Dimit's Law(LoD, Low of Demeter) ”。

Lod is also called "Principle of Least Knowledge (LKP, Principle of Least Knowledge)"There are many ways to paraphrase this principle. One of them is easier to understand: Don't talk to" strangers ", just communicate with your direct friends. So who is the stranger and who is the friend?
An object's friends fall into the following categories:
① The current object itself (this);
② The object that was passed as a parameter to the current object method;
③ The member object of the current object;
④ If the current item's member item is a collection, the items in the collection are also friends.
⑤ The object created by the current object.
Anyone who does not meet the above conditions is a stranger.