Background:
When some methods cannot be inherited, or meaningless, such as the shape class, then the interface of the base class cannot be implemented.
Then you need to introduce pure virtual functions.
Geometric base class:
Shape has draw method, triangle, circle, diamond and other draw methods are different. Only pure virtual functions can be used.
A base class with pure virtual functions is called an abstract class, and abstract classes cannot be instantiated, and pure virtual functions do not need to be implemented.
@ Definition of pure virtual function
#纯虚函数一般不需要实现.
@ Abstract class
Function: Abstract classes are declared as abstractions and design purposes, and the relevant data and behavior are organized in an integration hierarchy to ensure that derived classes have the required behavior.
For a function that cannot be implemented temporarily, it can be declared as a pure virtual function and left to the derived class for implementation.
Warning
1. Abstract class intelligence is used as a base class.
2. You cannot declare an abstract object.
3. A constructor cannot be a virtual function, and a destructor can be a virtual function.
@ Why destructors cannot be virtual functions?
If the constructor is a virtual function, then the virtual function table is not deterministic until the constructor is called, and the virtual function entry cannot be found before the instantiation, that is, the class cannot be constructed without dynamic binding.
So what about destructors?
In fact, the destructor of abstract class is supposed to be a virtual destructor function.
#include <iostream>#include<string>#include<vector>using namespacestd;classshape{ Public: ~Shape () {cout<<"~shape"<<Endl; } /*Virtual*/voidDraw () {cout<<"hehe"<<Endl; } };classCircle: Publicshape{ Public: voidDraw () {cout<<"Draw () ..."<<Endl; }};classSquare: Publicshape{ Public: voidDraw () {cout<<"Square () ..."<<Endl; }};voidDrawallshapes (Conststd::vector<shape*>&v) {std::vector<Shape*>:: Const_iterator it; for(It=v.begin (); It! = V.end (); it++) { (*it)Draw (); }}voidDeleteallshapes (Conststd::vector<shape*>&v) {std::vector<Shape*>:: Const_iterator it; for(It=v.begin (); It! = V.end (); it++) { Delete(*it); }}intMainintargcConst Char*argv[]) { //Shape S;//cannot instantiate an abstract classStd::vector<shape*>v; Shape*PS; PS=NewCircle; V.push_back (PS); PS=NewSquare; V.push_back (PS); Drawallshapes (v); return 0;}
If the draw method of the base class is not virtual, then it is a static binding, and the draw method of the call base class is determined during the compilation of the pointer in the main function, and we see the results printed:
? CPP ./a . Out hehehehe
If we change the draw method of the base class to virtual, then the draw method with the same name of the derived class is also virtual, then a virtual function table is maintained in the derived class, then it can be run again to determine which draw method to call.
#include <iostream>#include<string>#include<vector>using namespacestd;classshape{ Public: ~Shape () {cout<<"~shape"<<Endl; } Virtual voidDraw () =0 ; };classCircle: Publicshape{ Public: voidDraw () {cout<<"Draw () ..."<<Endl; }};classSquare: Publicshape{ Public: voidDraw () {cout<<"Square () ..."<<Endl; }};voidDrawallshapes (Conststd::vector<shape*>&v) {std::vector<Shape*>:: Const_iterator it; for(It=v.begin (); It! = V.end (); it++) { (*it)Draw (); }}voidDeleteallshapes (Conststd::vector<shape*>&v) {std::vector<Shape*>:: Const_iterator it; for(It=v.begin (); It! = V.end (); it++) { Delete(*it); }}intMainintargcConst Char*argv[]) { //Shape S;//cannot instantiate an abstract classStd::vector<shape*>v; Shape*PS; PS=NewCircle; V.push_back (PS); PS=NewSquare; V.push_back (PS); Drawallshapes (v); return 0;}
Results Print:
? CPP ./a . out Draw () ... Square () ...
Tip: The destructors class destructor is not a virtual function, then the fictional function of the derived class is not a virtual function
In the same way we can imagine that if you hold a derived class with the base class pointer ps in Main.
Then delete (PS);
shape* PS; New Square; Delete (PS);
Like the code above, the result will only call the base class's destructor, not the destructor of the derived class, and if the derived class has resources on the heap, the risk of a memory leak.
Look at the results.
#include <iostream>#include<string>#include<vector>using namespacestd;classshape{ Public: ~Shape () {cout<<"~shape"<<Endl; } Virtual voidDraw () =0 ; };classCircle: Publicshape{ Public: voidDraw () {cout<<"Draw () ..."<<Endl; }};classSquare: Publicshape{ Public: voidDraw () {cout<<"Square () ..."<<Endl; }};voidDrawallshapes (Conststd::vector<shape*>&v) {std::vector<Shape*>:: Const_iterator it; for(It=v.begin (); It! = V.end (); it++) { (*it)Draw (); }}voidDeleteallshapes (Conststd::vector<shape*>&v) {std::vector<Shape*>:: Const_iterator it; for(It=v.begin (); It! = V.end (); it++) { Delete(*it); }}intMainintargcConst Char*argv[]) { //Shape S;//cannot instantiate an abstract classStd::vector<shape*>v; Shape*PS; PS=NewCircle; V.push_back (PS); PS=NewSquare; V.push_back (PS); Drawallshapes (v); Deleteallshapes (v); return 0;}
Results Print:
Draw () ... Square () ... ~Shape~shape
The derived class destructor is not called correctly, and the square object can cause a memory leak when it is refactored.
Then we set the destructor of the base class to the virtual function, and then we look at the print result
? CPP ./a . out Draw () ... Square () ... ~Circle~Shape~Square~shape
If the base class destructor is a fictional function, it will be properly deconstructed. Call the destructor of the derived class itself first, and then call the destructor of the base class.
Summarize:
1. Abstract classes cannot be used to create object instances directly, but can declare pointers and references to abstract classes.
2. You can use pointers to abstract classes to support run-time polymorphism.
3. A pure virtual function in a base class must be implemented in a derived class, or it will still become an abstract class.
Here is an example of an abstract class that is commonly used, @ See comments
#include <iostream>using namespacestd;//for a class that does not have any interfaces, if you want to define it as an abstract class, you can only declare the virtual destructor as pure virtual//Typically, a pure virtual function in a base class does not need to be implemented//the exception is the pure virtual destructor to give the implementation. (Give an empty implementation)classbase{ Public: Virtual~base () =0 { }};classDriveD: Publicbase{};intMainvoid) {drived D; return 0;}
If the base class virtual destructor is not implemented, the compilation cannot pass.
C + + Learning Path: pure virtual function