Inheritance reflects the hierarchical relationship between classes
Polymorphism is to consider this hierarchical relationship and the relationship between specific member functions of the class itself to solve the problem of behavior re abstraction
5.1 static binding and dynamic binding
Polymorphism: the phenomenon that the same symbol or name has different interpretations in different situations.
c + + supports two polymorphisms:
- Compile time polymorphism
- Runtime polymorphism
For a function call, it is necessary to determine the code of the corresponding function body linked to it at compile time or at run time. This process is called function binding
Two linking methods of c + +
- Static binding
- Dynamic binding
Static binding (early binding)
Meaning: binding in the program compilation stage
The polymorphism supported by static binding is called compile time polymorphism
example:
//Meaning of static binding #include<iostream> const double PI=3.14; using namespace std; class Figure { public: Figure(){ }; double area()const{return 0.0;} }; class Circle:public Figure { public: Circle(double myr){R=myr;} double area() const{return PI*R*R;} protected: double R; }; class Rectangle:public Figure { public: Rectangle(double myl,double myw) { L=myl;W=myw; } double area()const{return L*W;} private: double L,W; }; int main() { Figure fig;//Base class object double area; area=fig.area(); cout<<"Area of figure is"<<area<<endl; Circle c(3.0); area=c.area(); cout<<"Area of circle is"<<area<<endl; Rectangle rec(4.0,5.0); area=rec.area(); cout<<"Area of rectangle is"<<area<<endl; return 0; }
result:
Area of figure is0 Area of circle is28.26 Area of rectangle is20
The biggest advantage of static binding is its high speed
According to the object assignment compatibility principle, the object of a base class can be compatible with the object of a derived class, the pointer of a base class can point to the object of a derived class, and a base class can reference the object of a derived class
//Meaning of static binding #include<iostream> const double PI=3.14159; using namespace std; class Figure { public: Figure(){ }; double area()const{return 0.0;} }; class Circle:public Figure { public: Circle(double myr){R=myr;} double area() const{return PI*R*R;} protected: double R; }; class Rectangle:public Figure { public: Rectangle(double myl,double myw) { L=myl;W=myw; } double area()const{return L*W;} private: double L,W; }; void func(Figure &p)//Formal parameters are references to base classes { cout<<p.area()<<endl; } int main() { Figure fig;//Base class object cout<<"Area of figure is"<<endl; func(fig); Circle c(3.0); cout<<"Area of circle is"<<endl; func(c); Rectangle rec(4.0,5.0); cout<<"Area of rectangle is"<<endl; func(rec); return 0; }
result
Area of figure is 0 Area of circle is 0 Area of rectangle is 0
reason:
void func(Figure &p);
The area() operation performed by the formal parameter p in is bound to the area() of the Figure class, so that only members with the same name inherited from the base class can be accessed. Dynamic binding can solve this problem.
Dynamic linking (late linking)
Definition: binding when the program is running
5.2 virtual function
Virtual function is the basis of dynamic binding
Function of virtual function
A virtual function is a member function that is declared inside a base class and redefined by a derived class.
Because of the existence of virtual function, it is possible to make dynamic connection
Dynamic binding needs to meet three conditions:
- Type compatibility principle
- Declare virtual function
- Virtual functions are called by member functions or through pointers and references.
#include<iostream> using namespace std; const double PI=3.14; class Figure { public: Figure(){}; virtual double area() const {return 0.0;} }; class Circle:public Figure { public: Circle(double myr){R=myr;} virtual double area() const {return PI*R*R;}//Defined as virtual function protected: double R; }; class Rectangle:public Figure { public: Rectangle(double myl,double myw){L=myl;W=myw;} virtual double area() const{return L*W;} private: double L,W; }; void func(Figure &p) { cout<<p.area()<<endl; } int main() { Figure fig; cout<<"Area of figure is"; func(fig); Circle c(3.0); cout<<"Area of circle is"; func(c); Rectangle rec(4.0,5.0); cout<<"Area of rectangle is"; func(rec); return 0; }
Difference between virtual function and general overloaded function
- Overloaded functions only require functions with the same function name, and overloaded functions are different functions with the same name defined in the same scope. Virtual functions require not only the same function name, but also the same signature and return type.
- Overloaded functions can be member functions or friend functions, and virtual functions can only be non static member functions
- Constructors can be overloaded, destructors cannot. Constructors cannot be defined as virtual functions, destructors can be defined as virtual functions.
- The call of overloaded functions is based on the difference of the passed parameter sequence, while virtual functions call virtual functions in different classes according to different objects
- Overloaded functions show polymorphism in the compilation process, which is static binding; The virtual function shows polymorphism at runtime, which is dynamic binding
Inherit virtual property down
The virtual function in the base class has the property of automatically passing to its derived class. No matter how many derived class layers, all functions with the same interface maintain the virtual property, because the derived class is also the base class.
The virtual function of a derived class redefining the base class is called coverage.
//Inherit virtual attributes #include <iostream> using namespace std; class Base //Base class { public: virtual int func(int x) //virtual function { cout <<"This is Base class "; return x; } }; class Subclass :public Base //Derived class { public: virtual int func(int x) //Virtual function, covering { cout <<"This is Sub class "; return x; } }; void test (Base& x) { cout<<"x= "<<x.func(5)<<endl; } int main ( ) { Base bc; Subclass sc; test (bc); test (sc); }
result
This is Base class x= 5 This is Sub class x= 5
Only overrides maintain the virtual property.
//Improper virtual function #include <iostream> using namespace std; class Base { public: virtual int func(int x) //The return type of the virtual function is int { cout <<"This is Base class "; return x; } }; class Subclass :public Base { public: virtual float func(int x) //The return type of the virtual function is float, which does not meet the coverage conditions { cout <<"This is Sub class "; float y=float(x); return y; } }; void test (Base& x) { cout<<"x= "<<x.func(5)<<endl; } int main ( ) { Base bc; Subclass sc; test (bc); test (sc); return 0; }
If the virtual functions of the derived class and the base class only have different return types and the rest are the same, c + + considers that an inappropriate virtual function is used.
//Missing virtual property #include <iostream> using namespace std; class Base { public: virtual int func(int x) //Virtual function, the formal parameter is of type int { cout <<"This is Base class "; return x; } }; class Subclass :public Base { public: virtual int func(float x) //Virtual function, the formal parameter is float type { cout <<"This is Sub class "; int y=float(x); return y; } }; void test (Base& x) { cout<<"x= "<<x.func(5)<<endl; } int main ( ) { Base bc; Subclass sc; test (bc); test (sc); return 0; }
If the virtual functions of the derived class and the base class have the same function name but different from each other, c + + is considered to redefine the function, which is hidden and loses the virtual feature.
The virtual function description in a class only affects the redefined functions in the derived class, but has no effect on the functions in its base class.
//The virtual function description does not affect the functions in its base class #include <iostream> using namespace std; class Base { public: int func(int x) { cout<<"This is Base class"; return x; } }; class Subclass1:public Base { public: virtual int func(int x) { cout<<"This is Sub1 class"; return x; } }; class Subclass2:public Subclass1 { public: int func(int x) { cout<<"This is Sub2 class"; return x; } }; int main ( ) { Subclass2 sc2; Base& bc=sc2; cout<<"x="<<bc.func(5)<<endl; Subclass1& sc1=sc2; cout<<"x="<<sc1.func(5)<<endl; return 0; }
result:
This is Base classx=5 This is Sub2 classx=5
5.3 calling virtual function in member function
The member function of a base class or derived class can directly call the virtual function in the class level
//Calling virtual function in member function #include <iostream> using namespace std; class Base { public: virtual void func1() { cout<<"This is Base func1()"<<endl; } void func2(){ func1(); } }; class Subclass:public Base { public: virtual void func1() { cout<<"This is Sub func1()"<<endl; } }; int main ( ) { Subclass sc; sc.func2(); return 0; }
result:
This is Sub func1()
In the case of public inheritance, the virtual function in member function will be dynamically linked.