多态

 

在面向对象的程序设计中,使用多态能够增强程序的可扩充性,即程序需要修改或增加功能时,只需改动或增加较少的代码。此外,使用多态也能起到精简代码的作用。

多态优点

  • 代码组织结构清晰
  • 可读性强
  • 利于前期和后期的扩展以及维护

 


 

初识多态

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 /*多态分为两类
 4 静态多态:函数重载和运算符重载属于静态多态,复用函数名
 5 动态多态:派生类和虚函数实现运行时多态
 6 
 7 静态多态和动态多态区别:
 8 静态多态的函数地址早绑定 - 编译阶段确定函数地址
 9 动态多态的函数地址晚绑定 - 运行阶段确定函数地址 
10 */
11 //动物类 
12 class Animal{
13     public:
14         //虚函数 
15         virtual void speak(){
16             cout<<"动物在说话"<<endl;
17         }
18 };
19 //猫类
20 class Cat:public Animal{
21     public:
22         void speak(){
23             cout<<"小猫在叫唤"<<endl;
24         }
25 };
26 
27 //狗类
28 class Dog:public Animal{
29     public:
30         void speak(){
31             cout<<"小狗在说话"<<endl;
32         }
33 }; 
34 
35 //执行说话的函数 
36 //地址早绑定 在编译阶段确定函数地址
37 //如果想执行让猫说话,那么这个函数地址就不能提前绑定
38 //需要在运行阶段进行绑定,地址晚绑定 
39 void doSpeak(Animal &animal){
40     animal.speak();    
41 }
42 
43 /*
44 动态多态满足条件
45 1、有继承关系
46 2、子类重写父类的虚函数 
47 //重写  函数返回值类型 函数名 参数列表 完全相同
48  
49  
50 动态多态使用
51 父类的指针或者引用 指向子类对象 
52 */
53 void test01(){
54     Cat cat;
55     doSpeak(cat);
56     Dog dog;
57     doSpeak(dog);
58 }
59 int main()
60 {
61     test01();
62     return 0;
63 }
初始多态
复制代码

对比普通写法与多态写法

复制代码
  1 #include <iostream>
  2 using namespace std;
  3 //案例描述:
  4 /*分别利用普通写法和多态技术,
  5 设计实现两个操作数进行运算
  6 的计算器类 
  7 */ 
  8 /*多态优点
  9 代码组织结构清晰
 10 可读性强
 11 利于前期和后期的扩展以及维护*/
 12 
 13 class Calculator{
 14 public:
 15     Calculator(int num1,int num2){
 16         m_Num1=num1;
 17         m_Num2=num2;
 18     }
 19     int getResult(string oper)
 20     {
 21         if(oper == "+"){
 22             return m_Num1+m_Num2;
 23         }
 24         else if(oper=="-"){
 25             return m_Num1 - m_Num2;
 26         }
 27         else if(oper == "*"){
 28             return m_Num1 * m_Num2;
 29         }
 30     }
 31     
 32     int m_Num1;
 33     int m_Num2;
 34 };
 35 
 36 //利用多态实现
 37 //多态好处:
 38 //1、组织结构清晰
 39 //2、可读性强
 40 //3、对于前期和后期拓展 
 41 
 42 class AbstractCalculator{
 43 public:
 44     virtual int getResult(){
 45         return 0;
 46     }
 47     
 48     int m_Num1;
 49     int m_Num2;
 50 }; 
 51 
 52 //加法计算器类
 53 class AddCalculator :public AbstractCalculator{
 54 public:
 55     int getResult(){
 56         return m_Num1+m_Num2;
 57     }
 58 }; 
 59 //减法计算器类
 60 class  SubCalculator :public AbstractCalculator{
 61 public:
 62     int getResult(){
 63         return m_Num1-m_Num2;
 64     }    
 65 };
 66 //乘法计算器类
 67 class  ProCalculator :public AbstractCalculator{
 68 public:
 69     int getResult(){
 70         return m_Num1*m_Num2;
 71     }    
 72 };
 73 void test01(){
 74     Calculator calculator(1,2);
 75 
 76     cout<<"calculator.getResult(1,2);oper=+; res="<<calculator.getResult("+")<<endl;
 77 }
 78 
 79 void test02(){
 80     //多态使用条件
 81     //父类指针或者引用指向子类对象
 82     
 83     //加法运算
 84     AbstractCalculator *abc = new AddCalculator;
 85     abc->m_Num1=10;
 86     abc->m_Num2=10;
 87     cout<<abc->m_Num1<<"+"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
 88     delete abc;
 89     //减法运算
 90     abc = new SubCalculator;
 91     abc->m_Num1=100;
 92     abc->m_Num2=90;
 93     cout<<abc->m_Num1<<"-"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
 94     delete abc;
 95     //乘法运算
 96     abc = new ProCalculator;
 97     abc->m_Num1=7;
 98     abc->m_Num2=8;
 99     cout<<abc->m_Num1<<"*"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
100     delete abc; 
101 }
102 
103 int main()
104 {
105 //    test01();
106     test02();
107     return 0;
108 }
多态案例1_计算器类
复制代码

纯虚函数与抽象类,一个父类指针访问调用不同子类的成员 

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 /*
 4 在多态中,通常父类中虚函数的实现是毫无意义的,
 5 主要都是调用子类重写的内容
 6 
 7 因此可以将虚函数改为纯虚函数
 8 
 9 纯虚函数语法:
10 virtual 返回值类型 函数名 (参数列表)=0;
11 
12 当类中有了纯虚函数,这个类也称为抽象类     
13 */
14 /*抽象类特点
15 无法实例化对象 
16 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
17  
18 */
19 
20  
21 class Base{
22     public:
23         //这就是纯虚函数 
24         virtual void func()=0;
25 }; 
26 
27 class Son:public Base{
28 public:
29     void func(){
30         cout<<"Son类的func()"<<endl;
31     }
32 };
33 
34 void test01(){
35     Son s;
36     s.func();
37     
38     //多态 一个父类指针访问调用不同子类的成员 
39     Base * base=new Son;
40     base->func();
41 }
42 int main()
43 {
44     test01();
45     return 0;
46 }
纯虚函数与抽象类
复制代码

体验纯虚函数与抽象类

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 /*
 4 制作饮品的大致流程为:
 5 煮水-冲泡-倒入杯中-加入辅料 
 6 */
 7 
 8 class AbstractDrinking{
 9     public:
10     virtual void Boil()=0;
11     virtual void Brew()=0;
12     virtual void PourInCup()=0;
13     virtual void PutSomething()=0;
14 
15     void makeDrink(){
16         Boil();
17         Brew();
18         PourInCup();
19         PutSomething();
20     }
21 };
22 
23 class Coffee:public AbstractDrinking{
24     public:
25         void Boil(){
26             cout<<"煮水"<<endl;
27         }
28         void Brew(){
29             cout<<"冲泡"<<endl;
30         } 
31         void PourInCup(){
32             cout<<"倒入杯中"<<endl;
33         }
34         void PutSomething(){
35             cout<<"加入牛奶和糖"<<endl;
36         }
37 };
38 
39 class Tea:public AbstractDrinking{
40     public:
41         void Boil(){
42             cout<<"煮水"<<endl;
43         }
44         void Brew(){
45             cout<<"冲泡茶叶"<<endl;
46         } 
47         void PourInCup(){
48             cout<<"倒入杯中"<<endl;
49         }
50         void PutSomething(){
51             cout<<"加入柠檬"<<endl;
52         }
53 };
54 void test01(){
55     AbstractDrinking *abs=new Coffee; 
56     abs->makeDrink();
57     cout<<"========================"<<endl;
58     abs=new Tea;
59     abs->makeDrink();
60     delete abs;
61 }
62 
63 int main()
64 {
65     test01();
66     return 0;
67 }
多态案例2_制作饮品
复制代码

利用虚析构可以解决 父类指针释放子类对象时不干净的问题 

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 
 4 
 5 /*多态使用时,如果子类中有属性开辟到堆区
 6 那么父类指针在释放时无法调用到子类的析构代码
 7 
 8 解决方式:将父类中的析构函数改为虚析构或者纯虚析构
 9  
10 */
11 /*虚析构和春虚析构共性:
12 可以解决父类指针释放子类对象
13 都需要有具体的函数实现 
14 */ 
15 /*虚析构和纯虚析构区别
16 如果是纯虚析构,该类属于抽象类,
17 无法实例化对象 
18 */
19 /*
20 虚析构语法
21 virtual -类名(){}
22 纯虚析构语法:
23 virtual ~类名()=0; 
24 */
25 
26 class Animal{
27     public:
28     Animal(){
29         cout<<"Animal的构造函数"<<endl;
30     }
31 ////利用虚析构可以解决 父类指针释放子类对象时不干净的问题 
32 //    virtual ~Animal(){
33 //        cout<<"Animal的析构函数"<<endl;
34 //    }
35 //纯虚析构
36     virtual ~Animal()=0; 
37         //纯虚函数
38     virtual void speak()=0; 
39 };
40 
41 Animal::~Animal(){
42     cout<<"Animal的纯虚析构函数"<<endl;
43 }
44 class Cat:public Animal{
45     public:
46         Cat(string name){
47             cout<<"这是Cat的构造函数"<<endl;
48             m_Name = new string(name);
49         }
50         void speak(){
51             cout<<*m_Name<<"小猫在说话"<<endl;
52         }
53         ~Cat(){
54             cout<<"这是Cat的析构函数"<<endl;
55             if(m_Name != NULL){
56                 delete m_Name;
57                 m_Name=NULL;
58             }
59         }
60         string *m_Name;
61 };
62 
63 void test01(){
64     
65     Animal * animal=new Cat("Tom");
66     animal->speak();
67     //父类指针在析构时候 不会调用子类中析构函数,
68     //导致子类如果有堆区属性 ,出现内存泄露 
69     delete animal;
70 }
71 
72 int main()
73 {
74     test01();
75     
76     
77     return 0;
78 }
虚析构和纯虚析构
复制代码

进一步体验,感受指针的使用。还看到有句弹幕“谁创建,谁清除”

复制代码
  1 #include <iostream>
  2 using namespace std;
  3 
  4 /*案例描述
  5 电脑主要组成部件为CPU(用于计算),显卡(用于显示),
  6 内存条(用于存储)将每个零件封装出抽象基类,并且提供
  7 不同厂商生产不同的零件,例如Intel厂商和lenovo
  8 厂商创建电脑类提供让电脑工作的函数,并且调用每个零件
  9 工作的接口,测试时组装三台不同的电脑进行工作 
 10 */
 11 
 12 class CPU{
 13     public :
 14         virtual void calculate()=0;
 15 }; 
 16 class VideoCard{
 17     public:
 18         virtual void display()=0;
 19 };
 20 class Memory{
 21     public:
 22         virtual void storage()=0;
 23 };
 24 class Computer{
 25     public:
 26         Computer(CPU * cpu,VideoCard *vc,Memory *mem){
 27             m_cpu=cpu;
 28             m_vc=vc;
 29             m_mem=mem;
 30         }
 31         //提供工作的函数
 32         void  work(){
 33             m_cpu->calculate();
 34             m_vc->display();
 35             m_mem->storage();
 36         }
 37         //提供析构函数 释放3个电脑零件
 38         ~Computer(){
 39             if(m_cpu!=NULL){
 40                 delete m_cpu;
 41                 m_cpu=NULL;
 42                 cout<<"m_cpu释放"<<endl;
 43             }
 44             if(m_vc!=NULL){
 45                 delete m_vc;
 46                 m_vc=NULL;
 47                 cout<<"m_vc释放"<<endl;
 48             }
 49             if(m_mem!=NULL){
 50                 delete m_mem;
 51                 m_mem=NULL;
 52                 cout<<"m_mem释放"<<endl;
 53             }
 54         } 
 55     private:
 56         CPU *m_cpu;
 57         VideoCard *m_vc;
 58         Memory * m_mem;
 59 };
 60 
 61 class IntelCPU:public CPU{
 62 public:
 63     virtual void calculate(){
 64         cout<<"IntelCPU开始计算了!"<<endl;
 65     }
 66 };
 67 class IntelVideoCard:public VideoCard{
 68 public:
 69     virtual void display(){
 70         cout<<"IntelVideoCard开始显示啦!"<<endl;
 71     }
 72 };
 73 class IntelMemory:public Memory{
 74 public:
 75     virtual void storage(){
 76         cout<<"IntelMemory开始存储了!"<<endl;
 77     }    
 78 };
 79 
 80 void test01(){
 81     CPU * intelCpu = new IntelCPU;
 82     VideoCard * intelCard = new IntelVideoCard;
 83     Memory * intelMem = new IntelMemory;
 84     Computer *IntelComputer=new Computer(intelCpu,intelCard,intelMem);
 85     IntelComputer->work();
 86     delete IntelComputer;
 87 }
 88 
 89 class LenovoCPU:public CPU{
 90 public:
 91     virtual void calculate(){
 92         cout<<"LenovoCPU开始计算了!"<<endl;
 93     }
 94 };
 95 class LenovoVideoCard:public VideoCard{
 96 public:
 97     virtual void display(){
 98         cout<<"LenovoVideoCard开始显示啦!"<<endl;
 99     }
100 };
101 class LenovoMemory:public Memory{
102 public:
103     virtual void storage(){
104         cout<<"LenovoMemory开始存储了!"<<endl;
105     }    
106 };
107 
108 void test02(){
109     CPU * lenovoCpu = new LenovoCPU;
110     VideoCard * lenovoCard = new LenovoVideoCard;
111     Memory * lenovoMem = new LenovoMemory;
112     Computer *LenovoComputer = new Computer(lenovoCpu,lenovoCard,lenovoMem);
113     LenovoComputer->work();
114     delete LenovoComputer;
115 }
116 int main()
117 {
118     test01();
119     cout<<"\r\n";
120     test02();
121     
122     cout<<"\r\n";
123     Computer *computer3 = new Computer(new LenovoCPU,new IntelVideoCard,new IntelMemory);
124     computer3->work();
125     delete computer3;
126     
127     return 0;
128 }
多态案例3_电脑组装
复制代码

 

posted @   HuangWQ289  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示