首页 > 其他分享 >多态

多态

时间:2023-09-07 22:56:41浏览次数:34  
标签:函数 int void 多态 public class

 

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

多态优点

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

 


 

初识多态

 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_电脑组装

 

标签:函数,int,void,多态,public,class
From: https://www.cnblogs.com/hwq123/p/17686249.html

相关文章

  • C++中的多态和虚函数
    #include<iostream>usingnamespacestd;//基类PeopleclassPeople{public:People(char*name,intage);voiddisplay();protected:char*m_name;intm_age;};People::People(char*name,int......
  • 重聊python封装继承多态
    继承以下是一段伪代码fromtorchimportnn.modelclassMODEL(nn.model): #继承了nn.mdoel类,可以自定义部分函数 defforward(self,x): x=self.linear1(x)x=self.batchnormal1d1(x)x=self.relu1(x) returnxpython可以继承一个类,在不改变类本身下,......
  • 【校招VIP】java语言考点之多态
    考点介绍:多态是校招常考考点之一。多态是面向对象程序设计(ooP)的一个重要特征,指同一个实体同时具有多种形式,即同个对象在不同时刻代表对象不一样,指的是对象的多种形态。答案详情解析和文章内容可扫下方海报二维码或点击链接即可查看!一、考点试题1、如何理解多态?类与对象的......
  • Java中的多态
    多态使用注意事项(1) (2)通俗一点,就是重写后的优先级更高,记住这点就好。默认状态下还是父亲优先 (3) (4)类型强制转换操作ps.Dog和Cat继承于Animal 1 //Animala=newDog();  1Animala=newCat(); ainstanceofDog方法用于判断a是否是Dog类型(ps.Dog是个类)----如果......
  • 21-面向对象编程-多态参数
    多态参数方法定义的形参类型为父类类型,实参类型允许为子类类型 员工类(父类):publicclassEmpolyee{privateStringname;privatedoublesalary;publicEmpolyee(Stringname,doublesalary){this.name=name;this.salary=salary;......
  • C++系列十:日常学习-非多态类型和多态类型
    目录介绍:案例:介绍:非多态类型和多态类型是C++中的两种类型,它们的主要区别在于是否包含虚函数和是否能进行动态绑定。非多态类型是指没有虚函数的类型。这种类型在编译时进行类型检查,因此不能在运行时改变其静态类型。对于非多态类型,编译器在编译时就已经确定了其所有信息,包括成......
  • 继承,多态,抽象类,接口
    一,继承1,概述-多个类中存在相同的属性和行为时,把这些相同的内容提取到一个独立的类中其他类就不用在重复定义这些内容,只需要通过extends关键字继承独立的类class子类extends父类{}有了继承后,我们就可以在一个已经存在的类的基础上,继续扩展新的成员classStudent{privateStringn......
  • android面试题:谈谈对Java中多态的理解
     Java中的多态是面向对象编程的一个重要特征,它允许同一个类型的对象在不同的情况下表现出不同的行为。多态是Java语言中实现代码复用、提高代码可维护性和可扩展性的重要手段。 多态的实现基于两个核心概念:继承和方法重写。在Java中,子类可以继承父类的方法,并且可以重写(覆......
  • 动态类型和静态类型以及多态
    一个对象的静态类型在编译的时候就确定了。一个对象的动态类型是指它指向的对象或则它绑定的对象(因此只有指针和引用才有动态类型),一个对象的动态类型只有编译的时候才会确定。1Quote*p=newb_Quote;//Quote是基类,b_Quote是子类指针p的静态类型是Quote,在编译......
  • C++的三大特性 ,封装、继承、多态?(一)
    C++的三大特性:封装、继承、多态。一、封装:将属性和行为作为一个整体,表现生活中的事物。一般来说就是把变量和函数一起放在一个类里,此时变量叫做成员变量,函数叫做成员函数。封装的意义一:将属性和行为作为一个整体,表现生活中的事物。1#include<iostream>2usingnamespaces......