6.1 overview
When a command is issued, different objects make different actions after receiving the same command.
Strictly speaking: the same object receives different messages, or different objects produce different actions when they receive the same message.
6.2 virtual function machine implementation principle
6.2.1 static polymorphism (early binding)
class Rect{ public: int calcArea(int width); int calcArea(int width,int height); };
In a rectangular class Rect defined, two member functions (with the same name) are defined, but the parameters of the two functions are different. They are overloaded functions.
Static binding: according to the number of parameters passed, the computer automatically calls the corresponding function during compilation, that is, in the compilation stage before running, the program of the function (which to call) has been determined.
6.2.2 dynamic polymorphism (late binding)
1. Chestnuts
Circular class and rectangular class (different objects) have their own computer area methods, but the methods are different, that is, they issue the same command to different objects, but do different operations.
The premise of dynamic polymorphism: Based on encapsulation and inheritance.
In a Shape class, Shape class defines a member function (calculate area):
class Shape{ public: double calcArea(){ cout<<"calcArea()"<<endl; return 0; } }
Define two more classes, both of which inherit the shape class in public.
The first is the circular class:
class Circle:public Shape{ public: Circle(double r){//Constructor m_dR=r; } double calcArea(); private: double m_dR; }; double Circle::calcArea(){ return 3.14*m_dR*m_dR; }
Then rectangular class:
class Rect:public Shape{ public: Rect(double width,double height){//Constructor m_dWidth=width; m_dHeigth=height; } double calcArea(); private: double m_dWidth; double m_dHeigth; }; double Rect::calcArea(){ return m_dWidth*m_dHeight; }
When used in the main function,
You can use the pointer shape1 of the parent class to point to one of the subclass objects Circle,
And use another parent class pointer shape2 to point to a rectangular object.
Both subclass objects are pointed to by their parent class pointers.
int main(){ Shape *shape1=new Circle(4.0); Shape *shape2=new Rect(3.0,5.0); shape1->calcArea(); shape2->calcArea(); return 0; }
The output result is 2 calcArea()
2. Virtual function:
Modify the member function of the class with virtual.
When defining the member function in the parent class shape, add the virtual keyword before the member function we want to implement polymorphism (make it a member virtual function):
Virtual function - "false" function. The parent class refers to the subclass object, and the subclass member function overrides the parent class method (function).
Writing method: add virtual before the calcArea function of the base class and virtual before the calcArea function declaration of the subclass Circle and Rect.
#include<stdlib.h> #include<iostream> #include<stdio.h> using namespace std; class Shape{ public: virtual double calcArea(){//virtual function cout<<"calcArea()"<<endl; return 0; } }; class Circle:public Shape{ public: //Circle(double r); virtual double calcArea(); Circle(double r){//Constructor m_dR=r; } private: double m_dR; }; double Circle::calcArea(){//Member function return 3.14*m_dR*m_dR; } class Rect:public Shape{ public: Rect(double width,double height){//Constructor m_dWidth=width; m_dHeigth=height; } virtual double calcArea(); private: double m_dWidth; double m_dHeigth; }; double Rect::calcArea(){//Implementation of member function return m_dWidth*m_dHeigth; } int main(){ Shape *shape1=new Circle(4.0); Shape *shape2=new Rect(3.0,5.0); cout<<shape1->calcArea(); cout<<shape2->calcArea(); system("pause"); return 0; }
The output result is no longer two calcArea(), but calls the calcArea() function of overriding the base class in the two subclasses to calculate the area of the circle and rectangle respectively.
Virtual function - "false" function. The parent class refers to the subclass object, and the subclass member function overrides the parent class method.
6.3 virtual function code practice
Define 2 pointers of Shape class in the calling program (one pointing to the subclass Rect and one pointing to the subclass Circle).
Use two pointers to call the function of calculating the area respectively - see whether the area function of the parent class or the child class is called;
Finally, destroy the two pointer objects -- see whether the objects of the subclass can be destroyed when the parent pointer is destroyed.
1. Project structure
2.3 header files
3.cpp document
#include "Circle.h" #include<iostream> using namespace std; Circle::Circle(double r){ cout<<"Circle()"<<endl; m_dR=r; } Circle::~Circle(){ cout<<"~Circle()"<<endl; } double Circle::calcArea(){ cout<<"Circle----calcArea"<<endl; return 3.14*m_dR*m_dR; }
#include<iostream> #include<stdlib.h> #include"Circle.h" #include"Rect.h" using namespace std; int main(){ Shape *shape1=new Rect(3,6);//Incoming width and height Shape *shape2=new Circle(5);//Incoming radius shape1->calcArea(); shape2->calcArea(); delete shape1; shape1=NULL; delete shape2; shape2=NULL; system("pause"); return 0; }
#include "Rect.h" #include<iostream> using namespace std; Rect::Rect(double width,double height){ cout<<"Rect()"<<endl; m_dWidth=width; m_dHeight=height; } Rect::~Rect(){ cout<<"~Rect()"<<endl; } double Rect::calcArea(){ cout<<"Rect----calcArea"<<endl; return m_dWidth*m_dHeight; }
Main function
#include"Shape.h" #include<iostream> using namespace std; Shape::Shape(){ cout<<"Shape()"<<endl; } Shape::~Shape(){ cout<<"~Shape()"<<endl; } double Shape::calcArea(){ cout<<"Shape---calcArea()"<<endl; return 0; }
Program analysis
(1) Results of the first four lines:
Instantiate a Rect object
——The constructor of the parent class will be executed first, and then its own constructor will be executed. The same is true for Circle instantiation.
(2) Middle two lines
We didn't call the calcArea() function in Rect and Circle as we thought
——Solution: add virtual before the calcArea() function in the three header files,
Note that the virtual before the calcArea function of the subclass does not have to be added. The system will add it automatically if it is not added, but it is best to add it.
Results after adding virtual:
(3) Last two lines
When destroying Shape1 and Shape2, only the destructors of the parent class are executed, and the destructors of the two subclasses are not executed.