Analysis of basic concepts and principles of polymorphism
Polymorphic
: Polymorphism is one of the three major features of C++ object-oriented. Polymorphisms are divided into static polymorphism and dynamic polymorphism.Static polymorphism
: Function overloading and operator overloading are static polymorphisms and multiplex function names.Dynamic polymorphism
: Derived classes and virtual functions implement runtime polymorphism.
the difference:
Static polymorphic function address binding is early, and the function address is determined during the compilation stage.
Dynamic polymorphic function address binding is late, and the function address is determined during the run.
#include <iostream> using namespace std; //Dynamic polymorphism meets the conditions//1. There is an inheritance relationship//2. Subclass rewrites the virtual function of the parent class. Rewrite refers to the return value. Function name. The parameters are exactly the same. Overload refers to the same function name.// Dynamic polymorphic use//Pointer or reference to the parent class, pointing to the child class object //When the subclass rewrites the virtual function of the parent class, the virtual function table in the subclass will be replaced with the virtual function address of the subclass, and replace &Animal::speak with &Cat::speak //Animalsclass Animal { public: //Virtual function virtual void speak(){ cout << "The animal is talking" << endl; } }; //Catsclass Cat :public Animal { public: void speak() { cout << "The kitten is talking" << endl; } }; //Dogsclass Dog :public Animal { public: void speak() { cout << "The puppy is talking" << endl; } }; //Execute the function of speaking//Address is bound early, and the address of the function is determined during the compilation stage//Although I want the cat to speak, the animal is being spoken here because the address is already bound//If you want the cat to speak, the address of this function cannot be bound in advance. It needs to be bound in the run phase, that is, the address is bound at a late stage.void DoSpeak(Animal &animal) { (); } void test01() { Cat cat; DoSpeak(cat); //Although I want the cat to speak, the animal is being spoken here, because the address is bound early. If the parent class is changed to a virtual function address and the cat is talking late, it means that the cat is talking Dog dog; DoSpeak(dog); } void test02() { cout << "size of Animal = " << sizeof(Animal) << endl; } int main() { //test01(); test02(); system("pause"); return 0; }
Polymorphic Case 1 Calculator Class
Using ordinary writing and polymorphic technology respectively, a calculator class is designed to implement two operands for operations.
Advantages of polymorphism
:
1. Clear code organization structure
2. Strong readability
3. Easy to expand and maintain in the early and later stages
#include<iostream> using namespace std; //Ordinary writingclass Calculate { public: int GetResult(string oper) { if (oper == "+") { return num1 + num2; } else if (oper == "-") { return num1 - num2; } else if (oper == "*") { return num1 * num2; } //If you want to expand new functions, you need to modify the original code. In actual development, the principle of opening and closing is advocated: develop the extension and close the modification. } int num1; int num2; }; void test01() { //Create a calculator object Calculate c; c.num1 = 10; c.num2 = 10; cout << c.num1 << " + "<< c.num2 << " = " <<("+") << endl; cout << c.num1 << " - "<< c.num2 << " = " <<("-") << endl; cout << c.num1 << " * "<< c.num2 << " = " <<("*") << endl; } //Use polymorphism to implement calculator//The advantages of polymorphism//1. Clear organizational structure//2. Highly readable//3. High performance for early expansion and later maintenance //Implement calculator abstract classclass AbstractCalculate { public: virtual int Result() { return 0; } int m_num1; int m_num2; }; //Addition calculator classclass AddCalculate : public AbstractCalculate{ public: int Result() { return m_num1 + m_num2; } }; //Subtraction calculator classclass SubCalculate : public AbstractCalculate { public: int Result() { return m_num1 - m_num2; } }; //Multiple calculator classclass MulCalculate : public AbstractCalculate { public: int Result() { return m_num1 * m_num2; } }; void test02() { // Use pointers in polymorphism // Parent class pointer or reference pointer to child class object //Addition operation AbstractCalculate* p = new AddCalculate; p->m_num1 = 100; p->m_num2 = 100; cout << p->m_num1 << " + " << p->m_num2 << " = " << p->Result() <<endl; //Release the newly opened heap area data after use delete p; //Subtraction operation p = new SubCalculate; p->m_num1 = 100; p->m_num2 = 100; cout << p->m_num1 << " - " << p->m_num2 << " = " << p->Result() << endl; delete p; //Multiple operation p = new MulCalculate; p->m_num1 = 100; p->m_num2 = 100; cout << p->m_num1 << " * " << p->m_num2 << " = " << p->Result() << endl; delete p; } int main() { //test01(); test02(); system("pause"); return 0; }
Pure virtual functions and abstract classes
In polymorphism, the virtual functions of the parent class function are usually meaningless, and are mainly rewrites by calling subclasses.
Therefore, virtual functions can be changed to pure virtual functions.
When pure virtual functions are found in the class, this class is also called an abstract class.
.Abstract class features
: The object cannot be instantiated; the subclass must re-abstract the pure virtual functions in the class, otherwise it also belongs to the abstract class.
#include<iostream> using namespace std; //Pure virtual function syntax virtual return value Function name (parameter list) = 0;//When there is a pure virtual function in the class, this class is also called an abstract class. The abstract class cannot instantiate an object. The subclass must rewrite the pure virtual function in the abstract class, otherwise the subclass also belongs to the abstract class.class Base { public: //Pure virtual functions As long as there is a pure virtual function, this class is an abstract class virtual void func() = 0; }; class Son :public Base { public: void func() { cout << "Func function call under Son class" << endl; } }; void test01() { /*Abstract classes cannot instantiate objects Base b; new Base;*/ Son s; (); //Polymorphic method call parent class pointer new a child class Base* p = new Son; p->func(); delete p; } int main() { test01(); system("pause"); return 0; }
Polymorphic Case 2 Make a Drink
Use polymorphic technology to realize the process of making drinks, provide abstract beverage production bases, and provide subcategories to make coffee and tea.
The reason why pointer polymorphism is used here instead of reference is that references need to instantiate the object first, but abstract classes with pure virtual functions cannot instantiate the object.
#include<iostream> using namespace std; class AbstractDrinking { public: //Boil water virtual void Boil() = 0; //Brew virtual void Brew() = 0; //Pour into a cup virtual void DropInCup() = 0; //Add auxiliary materials virtual void AddSomething() = 0; //Make drinks void MakeDrink() { Boil(); Brew(); DropInCup(); AddSomething(); } }; //The process of making coffeeclass Coffee : public AbstractDrinking { public: //Boil water virtual void Boil() { cout << "Cook a pot of boiling water" << endl; } //Brew virtual void Brew() { cout << "Brew coffee powder" << endl; } //Pour into a cup virtual void DropInCup() { cout << "Populate coffee into a cup" << endl; } //Add auxiliary materials virtual void AddSomething() { cout << "Add milk and sugar to coffee" << endl; } }; //The process of making teaclass Tea : public AbstractDrinking { public: //Boil water virtual void Boil() { cout << "Cook a pot of boiling water" << endl; } //Brew virtual void Brew() { cout << "Brewing in the West Lake Longjing" << endl; } //Pour into a cup virtual void DropInCup() { cout << "Populate tea into a cup" << endl; } //Add auxiliary materials virtual void AddSomething() { cout << "Add wolfberry into tea" << endl; } }; //Produce a drink functionvoid DoWork(AbstractDrinking *p) { //This is equivalent to AbstractDrinking *p = new Coffee; //If you do not use pointers here and instead refer to a reference, the function of test01 cannot be used //Because the reference is to instantiate the object first and then call the object, the abstract class cannot instantiate the object p->MakeDrink(); delete p; //Prevent memory leakage, remember to free memory after use} void test01() { // Want to have a cup of coffee DoWork(new Coffee); cout << "-----------------------------------" << endl; //I want to have a cup of West Lake Longjing Tea DoWork(new Tea); } int main() { test01(); system("pause"); return 0; }
Virtual destruction and pure virtual destruction
When using polymorphic technology, if a subclass is opened to the heap area, the parent class pointer cannot call the subclass's destructor code when it is released. The solution to this problem is
Change the destructor in the parent class to virtual destructor or pure virtual destructor
。
Commonality of virtual destruction and pure virtual destruction
:
1. It can solve the problem of releasing child object by parent class pointer
2. All need specific function implementationsThe difference between virtual destruction and pure virtual destruction
:
If it is pure virtual destruction, this class belongs to an abstract class and cannot instantiate the object.
#include<iostream> #include<string> using namespace std; //Animalsclass Animal { public: Animal() { cout << "This is an Animal constructor call" << endl; } //Pure virtual function virtual void Speak() = 0; //In order to use the subclass's fiction function, the parent class's fiction function needs to be changed to virtual destructor /*virtual ~Animal() { cout << "This is Animal's destructor call" << endl; }*/ //Pure virtual destructor The heap area of the parent class may also be opened and released, so the destruction of the parent class must also be declared and implemented. //After pure virtual destruction, this class also belongs to an abstract class and cannot instantiate objects virtual ~Animal() = 0; }; Animal:: ~Animal() { cout << "This is a pure virtual destructor call written outside of the Animal class" << endl; } //Catsclass Cat : public Animal{ public: //Constructor of Cat class Cat(string name) { cout << "This is the constructor of the Cat class" << endl; m_name = new string(name); } void Speak() { cout << *m_name<<"The kitten's cry" << endl; } ~Cat() { if (m_name != NULL) { //When the parent class pointer is destructed, the destructor in the subclass will not be called, resulting in the data opened by the heap area in the subclass that is not released cleanly, resulting in memory leakage cout << "This is the destructor of the Cat class" << endl; delete m_name; m_name = NULL; } } string *m_name; }; void test01() { Animal* p = new Cat("Tom"); //If there is no heap area data in the subclass, you can not write virtual destructors or pure virtual destructors p->Speak(); delete p; //After the stack area is opened, release the pointer} int main() { test01(); system("pause"); return 0; }
Polymorphic Case 3 Computer Assembly
The main components of the computer are CPU, graphics card and memory stick. Package each part into an abstract base class and provide different parts to different manufacturers. Create a computer class to provide functions that make the computer work and call the interface for each part to work. During the test, three different computers were assembled for work.
#include<iostream> using namespace std; //Each part is encapsulated with abstract base class//CPU classclass Cpu { public: //Abstract calculation functions virtual void Calculate() = 0; //virtual ~Cpu() = 0; }; //Cpu::~Cpu() { // cout << "The pure virtual destructor call written outside the Cpu class" << endl;//} //Graphics Cardsclass VideoCard { public: //Abstract display function virtual void Display() = 0; }; //Memory Stamp Classclass Memory { public: //Abstract storage functions virtual void Storage() = 0; }; //Computerclass Computer { public: Computer(Cpu* cpu, VideoCard* videocard, Memory* memory) { m_cpu = cpu; m_videocard = videocard; m_memory = memory; } //Working function: Working interface that makes parts call. The parent class pointer is already a polymorphic technology when calling the interface. void DoWork() { //Cpu performs calculation operations m_cpu->Calculate(); //Graphics card display operation m_videocard->Display(); // Memory sticks perform storage operations m_memory->Storage(); } //Providing a destructor to release three parts of the computer ~Computer() { if (m_cpu != NULL) { delete m_cpu; m_cpu = NULL; } if (m_videocard != NULL) { delete m_videocard; m_videocard = NULL; } if (m_memory != NULL) { delete m_memory; m_memory = NULL; } } private: Cpu *m_cpu; VideoCard *m_videocard; Memory *m_memory; }; //Specific manufacturer/////Intel manufacturerclass IntelCpu :public Cpu{ public: //Subclass overrides the virtual function of the parent class virtual void Calculate() { cout << "Intel's CPU has started to calculate!" << endl; } /*~IntelCpu() { cout << "This is a destructor call to subclass IntelCpu" << endl; }*/ }; class IntelVideoCard :public VideoCard { public: //Subclass overrides the virtual function of the parent class virtual void Display() { cout << "Intel's graphics card starts to display the screen!" << endl; } }; class IntelMemory :public Memory { public: //Subclass overrides the virtual function of the parent class virtual void Storage() { cout << "Intel's memory stick has started storing data!" << endl; } }; //Lenovo manufacturerclass LenovoCpu :public Cpu { public: //Subclass overrides the virtual function of the parent class virtual void Calculate() { cout << "Lenovo's CPU starts to calculate!" << endl; } }; class LenovoVideoCard :public VideoCard { public: //Subclass overrides the virtual function of the parent class virtual void Display() { cout << "Lenovo's graphics card starts to display the screen!" << endl; } }; class LenovoMemory :public Memory { public: //Subclass overrides the virtual function of the parent class virtual void Storage() { cout << "Lenovo's memory stick has started storing data!" << endl; } }; //Start test and assemble different computersvoid test01() { // Parts of the first computer //The parent class pointer points to the subclass object, using polymorphic technology Cpu* intelcpu = new IntelCpu; VideoCard* intelvideocard = new IntelVideoCard; Memory* intelmemory = new IntelMemory; //Create the first computer cout << "The first assembled computer is configured as follows:" << endl; Computer* computer1 = new Computer(intelcpu,intelvideocard,intelmemory); computer1->DoWork(); delete computer1; //Create a second computer cout << "The second assembled computer is configured as follows:" << endl; Computer* computer2 = new Computer(new LenovoCpu, new LenovoVideoCard, new LenovoMemory); computer2->DoWork(); delete computer2; //Create a third computer cout << "The assembled third computer is configured as follows:" << endl; Computer* computer3 = new Computer(new LenovoCpu, new IntelVideoCard, new LenovoMemory); computer3->DoWork(); delete computer3; } int main() { test01(); system("pause"); return 0; }
This is the end of this article about the detailed explanation of polymorphism of C++ classes and objects. For more related polymorphism content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!