Polymorphism is one of the basic features of object-oriented programming. The polymorphism is realized by virtual function.
- Binding mode and Polymorphism
first, the basic concept
Polymorphism: Methods and functions have the same name, but have different behaviors.
binding : The function call corresponds to a function body.
early binding , and static binding : The binding is completed during the compilation phase.
late binding , and dynamic binding : Binding is completed at run time.
compile-time polymorphism : Determine the meaning of a name in the compilation phase, implemented in the C + + language through function overloading and template mechanism.
Runtime polymorphism : The meaning of the name is determined at run time, and the virtual function is combined with the inheritance mechanism and dynamic binding mechanism in the C + + language.
In the C + + language, the default binding of a function call is a static binding, and only a member function that is specified as a virtual function is dynamically bound by a reference to a base class type or a pointer call. Obtaining run-time polymorphism requires the following conditions to be met:
A has a hierarchy of inheritance;
b define the virtual function in the base class;
C redefine the virtual function defined in the base class in the derived class;
D calls a virtual function from a base class pointer (or base class reference).
The basis of runtime polymorphism is the type compatibility of a public derived class against a base class, that is, a pointer to a base class object that points to a public derived class object of that base class (similarly, a reference to a base class object can also be associated to a public derived class object of that base class). When declaring a pointer (reference) variable, the base type specified is called a static type of pointer (or reference), and the type of the object to which the pointer variable actually points (or refers to the variable is actually associated) is called a dynamic type of pointer (or reference).
Ii. The role of polymorphism
Polymorphism enables programmers to define multiple operations or functions using the same name, to name the same identifier for a similar operation or function, to enhance the program's modifiable and extensible nature, and to respond effectively to changes in requirements when developing programs.
Object-oriented Programming approach organizes the program around objects, that is, according to the entity design program, the "object" concept as the core, around objects and classes (not functions) to organize the code, encapsulation makes the object data and operation of the implementation are shielded, unaffected by the outside world.
A virtual function is a member function that uses the reserved word virtual declaration in the class definition body.
A polymorphic class that refers to a class that contains virtual functions.
The virtual functions defined in the base class are redefined in one or more derived classes in the public inheritance hierarchy, and run-time polymorphism is implemented by calling virtual functions by pointers to the base class (or base class references).
example of a virtual function
In addition to constructors, any non-static member function can be designed as a virtual function as needed.
Where the constructor cannot be designed as a virtual function, because the constructor runs before the object is fully constructed, the type of the object is incomplete when the constructor is run, and the static member function cannot be designed as a virtual function because the static member function is shared by all instances of the class and does not belong to an object.
Example 1:
/* Dynamic binding of virtual functions */#include <iostream>using namespace std;class base{public:virtual void ShowName () {cout << "Base Class "<< Endl;}}; Class DClass1:p ublic base{public:void showname ()//redefinition of inherited members {cout << "the first derived class" << endl;}; Class DClass2:p ublic base{public:void showname ()//redefinition of inherited members {cout << "the second derived class" << endl;}; int main () {Base bobj;dclass1 d1obj;dclass2 d2obj; Base *ptr;//defines a pointer to a base class ptr = &bobj;ptr->showname ();p tr = &d1obj;//base class pointer to a derived class object Ptr->showname ();p tr = & The d2obj;//base class pointer points to the derived class object Ptr->showname (); System ("pause"); return 0;}
Operation Result:
Base class
The first derived class
The second derived class
Analysis:
Dynamic binding can use a member function defined in a different class in a uniform way, that is, calling a virtual function defined in a derived class or base class in the same way (the function name), and dynamic binding does not need to care about the concrete type of the object when calling the virtual function.
Note: If a non-virtual member function is called through a pointer, the call is only relevant to the base type of the pointer, regardless of the object that the pointer is currently pointing to. If you remove the virtual reserved word in the ShowName declaration of the member function in the base class base in the program, the result is:
Base class
Base class
Base class
Because the base type of PTR is base, static binding is used for calls to non-virtual functions.
Example 2:
/* Dynamic binding via base class reference */#include <iostream>using namespace std;class base{public:virtual void ShowName () {cout << Base class "<< Endl;}}; Class DClass1:p ublic base{public:void showname ()//redefinition of inherited members {cout << "the first derived class" << endl;}; Class DClass2:p ublic base{public:void showname ()//redefinition of inherited members {cout << "the second derived class" << endl;}; void printidentity (base& obj) {obj.showname ();} int main () {Base bobj;dclass1 d1obj;dclass2 d2obj;printidentity (bobj);p rintidentity (d1obj);p rintidentity (D2OBJ); System ("pause"); return 0;}
Attention:
The virtual function defined in the base class is still a virtual function in the derived class, regardless of whether the virtual reserved word is specified in the derived class.
A virtual function is specified simply by adding the reserved word to the member function declaration in the class definition body, which cannot be used on the definition of a member function outside the body of the class definition, or a compilation error will occur.
Ii. using a specific version of a virtual function
In some specific cases, the programmer may want to override the above default virtual function call mechanism, forcing a function call to use a specific version of a virtual function. The most common scenario is to call the corresponding version in the base class in a derived class virtual function so that the base class version can be reused to complete all types of public tasks in the inheritance hierarchy, and each derived type only adds its own special work to the version of the virtual function of this class.
Example:
It is assumed that the general student and graduate students should be managed in a college student management program, so that a student class student and a postgraduate class graduatestudent can be defined. Because graduate students are a kind of student, they can define graduate class graduatestudent by inheriting students ' class student.
Students generally have a name, school number, professional, grade and other basic information, graduate students in addition to the basic information, generally also have mentors, categories and other information.
Assuming that the class student provides virtual functions DisplayInfo display basic information about the student object, the class Graduatestudent redefine the DisplayInfo function to show the basic information of the Postgraduate object.
Define these two functions:
Class student{public:virtual void DisplayInfo () {cout << stuid << endl;cout << name << endl;cout &L t;< sex << endl;cout << major << Endl;} Omit the definition of other Members};class Graduatestudent:public student{public:void displayinfo () {Student::d isplayinfo ();// Call the base class's DisplayInfo function output basic information cout << type << endl;//output graduate student-specific information cout << advisor << Endl;} Omit the definition of another member};
Attention:
When you call the base class version in a derived class virtual function, you must use the scope resolution operator. If the scope resolution operator is missing, the function call is determined at run time and will be a self-invocation, resulting in infinite recursion.
third, virtual destructor function
In general, it is best to define a virtual destructor in the root class of the inheritance hierarchy. Because when you delete a pointer to a dynamically allocated object, that is, when you undo a dynamically created object, you need to call the appropriate destructor to clear the object.
When an object in an inheritance hierarchy is revoked, the static type of the pointer may be different from the type of the object actually being revoked, when a delete operation is performed on such a pointer, the destructor in the Destructors class is not a virtual function, and only the destructor of the base class is called, not the destructor of the derived class. This may result in an incorrect object revocation operation: The destructor of the derived class is not called.
Example:
/* Call to Non-virtual destructor */#include <iostream>using namespace Std;class base{public:~base () {cout << "Base destructor" << Endl;}}; Class DClass:p ublic base{public:~dclass () {cout << "Derived class destructor" << Endl;}}; int main () {base *ptr;//defines a pointer to the base class ptr = new dclass;//dynamically creates a derived class object//omits the use of PTR with delete ptr;//dynamically revokes the derived class object system ("pause"); return 0 ;}
Execution Result:
Base destructor
Analysis:
Although the pointer ptr actually points to the object of the derived class dclass, the actual execution is to undo the operation of the base class object, so the destructor of the base class base is called, and the destructor of the derived class Dclass is not called.
There is no problem if there is nothing substantial in the destructor of the derived class, but there is an action in the destructor of the derived class (such as when a pointer member is contained in a derived class, the destructor typically deletes the member pointer to release the memory pointed to by the pointer member). The delete operation on the base class pointer does not cause a problem when the destructor of the derived class is called (such as the memory that the pointer member of the derived class object points to will not be freed).
If you define a destructor in the base class, you will avoid these problems and ensure that the appropriate destructor is executed. If the destructor of the base class is specified as a virtual function in the program, the result is run:
Derived class destructor
Base destructor
Attention:
Derived classes must declare each inherited member that you want to redefine. When you declare a virtual function that is defined in a base class in a derived class, you typically have the exact same prototype (including the function name and formal parameter list) as the functions.
There are two exceptions to this rule: one is that the destructor of the derived class does not have the same name as the destructor of the base class, and the other is that the virtual function in the Destructors class returns a pointer (or reference) of a type x, and the corresponding virtual function in the derived class can return a pointer (or reference) to a derived class of type X
- Pure virtual functions and abstract classes
One, pure virtual function
The inheritance mechanism is characterized by the relationship between the generality and individuality of the categories of things (entities). Therefore, in an inheritance hierarchy, the base class represents the commonality that all derived classes have, and each derived class represents the personality peculiar to this class, respectively. The required function in a base class identifies a common operation, and the redefinition of a virtual function in a derived class experiences the particularity of the operation in the derived class. If a derived class does not redefine a virtual function in the base class, the version defined in the base class is used.
In many cases, however, we cannot give a clear definition of a virtual function in a base class, and a pure virtual function is used to indicate that a virtual function cannot be defined in a base class.
A pure virtual function is a virtual function declared in a base class, but does not define a function body in the base class, requiring any derived class to define its own version.
The general scenario for declaring a pure virtual function is as follows:
Virtual return value type function name (formal parameter list) = 0;
That is, add a = 0 to the declaration of the general virtual function to indicate that the function is a pure virtual function.
second, abstract class
1 definitions
Abstract class refers to a class that contains pure virtual functions.
2 Features
Can only be used as a base class for other classes;
cannot be used to create object instances directly;
cannot be used as a function parameter type, return value type;
Cannot be used to force type conversions;
A pointer and reference to an abstract class can be declared;
Example:
Class account{public:virtual bool Deposit (int account) = 0;virtual bool Withdraw (int. account) = Definition of other members in the 0;//class omitted}; Account *ptr;//declares the abstract class account pointer account& fun3 (account& a);//abstract class references do function parameters and return value types//Account x;// An object that declares an abstract class account (creates an object instance of an abstract class)//Account fun1 (int);//abstract class as the function's return value type//void Fun2 (account a);//abstract class as the parameter type of the function
Attention:
If a derived class inherits an abstract class, but the derived class does not redefine all pure virtual functions in the abstract base class, the derived class is also an abstract class.
Polymorphism and virtual functions