随笔 - 110,  文章 - 0,  评论 - 0,  阅读 - 18441

 多态的基本概念

多态是C++面向对象三大特性之一

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
复制代码
 1 #include <iostream>
 2 using namespace std;
 3 //animal class
 4 class animal
 5 {
 6 public:
 7     //虚函数
 8     virtual void speak()
 9     {
10         cout << "动物在说话" << endl;//不加virtual就是早绑定,加了就是晚绑定
11     }
12 };
13 //cat class
14 class cat : public animal
15 {
16 public:
17     //重写 函数返回值类型 函数名 参数列表 完全相同
18     void speak()
19     {
20         cout << "小猫在说话" << endl;
21     }
22 };
23 //dog class
24 class dog : public animal
25 {
26 public:
27     void speak()
28     {
29         cout << "小狗在说话" << endl;
30     }
31 };
32 //执行说话的函数
33 //地址早绑定 在编译阶段确定函数地址
34 //如果想执行让猫说话 那么这个函数地址就不能提前绑定 需要在运行阶段进行绑定,也就是地址晚绑定
35 
36 //动态多态满足条件
37 //1.得有继承关系
38 //2.子类重写父类虚函数
39 
40 //动态多态的使用
41 //父类的指针或引用 执行子类的对象
42 void dospeak(animal& Animal)//animal & Animalv= cat;
43 {
44     Animal.speak();
45 }
46 void test01()
47 {
48     cat ca;//父类的引用指向子类对象
49     dospeak(ca);
50     dog dogg;
51     dospeak(dogg);
52 }
53 int main()
54 {
55     test01();
56 }
复制代码

 多态原理剖析:

 

 

 

 

 

 

 

 

 未重写时:

 

 

 重写后:

 

 

总结:

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数

多态使用条件

  • 父类指针或引用指向子类对象

重写:函数返回值类型 函数名 参数列表 完全一致称为重写

 

多态案例一-计算器类

案例描述:

分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类

多态的优点:

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

普通写法:

复制代码
 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 class calculator
 5 {
 6 public:
 7     int geresult(string oper)
 8     {
 9         if (oper == "+")
10         {
11             return n_num1 + n_num2;
12         }
13         else if (oper == "-")
14         {
15             return n_num1 - n_num2;
16         }
17         else if (oper == "*")
18         {
19             return n_num1 * n_num2;
20         }
21         else if (oper == "/")
22         {
23             return n_num1 / n_num2;
24         }
25     }
26     int n_num1;//操作数1
27     int n_num2;//操作数2
28 };
29 void test01()
30 {
31     //创建计算器的对象
32     calculator c;
33     c.n_num1 = 10;
34     c.n_num2 = 10;
35     cout << c.n_num1 << "+" << c.n_num2  << "=" <<c.geresult("+") << endl;
36     cout << c.n_num1 << "-" << c.n_num2 << "=" << c.geresult("-") << endl;
37     cout << c.n_num1 << "*" << c.n_num2 << "=" << c.geresult("*") << endl;
38     cout << c.n_num1 << "/" << c.n_num2 << "=" << c.geresult("/") << endl;
39 }
40 int main()
41 {
42     test01();
43 }
复制代码

 

 多态写计算器类

复制代码
  1 #include <iostream>
  2 #include <string>
  3 using namespace std;
  4 class calculator
  5 {
  6 public:
  7     int geresult(string oper)
  8     {
  9         if (oper == "+")
 10         {
 11             return n_num1 + n_num2;
 12         }
 13         else if (oper == "-")
 14         {
 15             return n_num1 - n_num2;
 16         }
 17         else if (oper == "*")
 18         {
 19             return n_num1 * n_num2;
 20         }
 21         else if (oper == "/")
 22         {
 23             return n_num1 / n_num2;
 24         }
 25         //如果想拓展新功能,需求修改源码
 26         //在真正的开发中 提倡开闭原则
 27         //开闭原则 对拓展进行开放,对修改进行关闭
 28     }
 29     int n_num1;//操作数1
 30     int n_num2;//操作数2
 31 };
 32 //利用多态来实现计算器
 33 // 多态好处
 34 //1: 组织结构清晰
 35 //2:可读性强
 36 //3:对于前期和后期的维护性高
 37 //实现计算器抽象类
 38 class abstractcalculator
 39 {
 40 public:
 41     virtual int getresult()
 42     {
 43         return 0 ;
 44     }
 45     int m_num1;
 46     int m_num2;
 47 };
 48 //加法计算器类
 49 class addcalculatator : public abstractcalculator 
 50 {
 51 public:
 52     int getresult()
 53     {
 54         return m_num1 + m_num2;
 55     }
 56 };
 57 //减法计数器的类
 58 class subcalculatator : public abstractcalculator
 59 {
 60 public:
 61     int getresult()
 62     {
 63         return m_num1 - m_num2;
 64     }
 65 };
 66 //乘法计算器类
 67 class mulcalculatator : public abstractcalculator
 68 {
 69 public:
 70     int getresult()
 71     {
 72         return m_num1 * m_num2;
 73     }
 74 };
 75 //除法计算器类
 76 class divicalculatator : public abstractcalculator
 77 {
 78 public:
 79     int getresult()
 80     {
 81         return m_num1 / m_num2;
 82     }
 83 };
 84 void test02()
 85 {
 86     //多态使用条件
 87     //父类指针或者引用指向子类对象
 88     //加法运算
 89     abstractcalculator* abc = new addcalculatator;
 90     abc->m_num1 = 10;
 91     abc->m_num2 = 10;
 92     cout << abc->m_num1 << "+" << abc->m_num2 << "=" << abc->getresult() << endl;
 93     //用完后记得销毁
 94     delete abc;
 95     //减法运算
 96     abc = new subcalculatator;
 97     abc->m_num1 = 10;
 98     abc->m_num2 = 10;
 99     cout << abc->m_num1 << "-" << abc->m_num2 << "=" << abc->getresult() << endl;
100     delete abc;
101     //乘法运算
102     abc = new mulcalculatator;
103     abc->m_num1 = 10;
104     abc->m_num2 = 10;
105     cout << abc->m_num1 << "*" << abc->m_num2 << "=" << abc->getresult() << endl;
106     delete abc;
107     //除法运算
108     abc = new divicalculatator;
109     abc->m_num1 = 10;
110     abc->m_num2 = 10;
111     cout << abc->m_num1 << "/" << abc->m_num2 << "=" << abc->getresult() << endl;
112     delete abc;
113 
114 }
115 int main()
116 {
117     test02();
118 }
复制代码

 

 总结:C++开发提倡利用多态设计程序架构,因为多态优点很多

纯虚函数和抽象类

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 //纯虚函数和抽象类
 4 class base
 5 {
 6 public:
 7     //纯虚函数
 8     //只要有一个纯虚函数,这个类称之为抽象类
 9     //抽象类特点
10     //1.无法实例化对象
11     //2.抽象类的子类 必须重写父类中的纯虚函数,否则也属于抽象类
12     virtual void func() = 0;
13 };
14 class son : public base
15 {
16 public:
17     virtual void func()
18     {
19         cout << "func 函数的调用" << endl;
20     }
21 };
22 void test01()
23 {
24 //    base b;//抽象类 无法实例化对象
25 //    new base;//抽象类 无法实例化对象 
26     //son s;  //子类必须重写父类中的纯虚函数 否则无法实例化对象
27     base* ba = new son;
28     ba->func();
29 }
30 int main()
31 {
32     test01();
33 }
复制代码

 

 

 

 

 

 

 

 

多态案例二-制作饮品

案例描述:

制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料

利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 class abcstractdrink
 4 {
 5 public:
 6     //煮水
 7     virtual void boil () = 0;
 8     //冲泡
 9     virtual void brew() = 0;
10     //倒入杯中
11     virtual void pourcup() = 0;
12     //加入辅料
13     virtual void  putsomething() = 0;
14     //制作饮品
15     void makedrink()
16     {
17         boil();
18         brew();
19         pourcup();
20         putsomething();
21     }
22 };
23 //制作咖啡
24 class coffe : public abcstractdrink
25 {
26 public:
27     //煮水
28     virtual void boil()
29     {
30         cout << "煮农夫山泉" << endl;
31     }
32     //冲泡
33     virtual void brew()
34     {
35         cout << "冲泡咖啡" << endl;
36     }
37     //倒入杯中
38     virtual void pourcup()
39     {
40         cout << "倒入杯中" << endl;
41     }
42     //加入辅料
43     virtual void  putsomething()
44     {
45         cout << "加入糖和牛奶" << endl;
46     }
47 };
48 //制作茶叶
49 class tea : public abcstractdrink
50 {
51 public:
52     //煮水
53     virtual void boil()
54     {
55         cout << "煮矿泉水" << endl;
56     }
57     //冲泡
58     virtual void brew()
59     {
60         cout << "冲泡茶叶" << endl;
61     }
62     //倒入杯中
63     virtual void pourcup()
64     {
65         cout << "倒入杯中" << endl;
66     }
67     //加入辅料
68     virtual void  putsomething()
69     {
70         cout << "加入枸杞" << endl;
71     }
72 };
73 //制作函数
74 void dowork(abcstractdrink* abs)//abcstractdrink* abs = new coffe
75 {
76     abs->makedrink();
77     delete abs;
78 }
79 
80 void test01()
81 {
82     //制作咖啡函数
83     dowork(new coffe);//abcstractdrink* abs = new coffe
84     cout << "-----------------------------" << endl;
85     //制作茶叶
86     dowork(new tea);
87 }
88 int main()
89 {
90     test01();
91 }
复制代码

 

 

虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

解决方式:将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

复制代码
 1 class Animal {
 2 public:
 3 
 4     Animal()
 5     {
 6         cout << "Animal 构造函数调用!" << endl;
 7     }
 8     virtual void Speak() = 0;
 9 
10     //析构函数加上virtual关键字,变成虚析构函数
11     //virtual ~Animal()
12     //{
13     //    cout << "Animal虚析构函数调用!" << endl;
14     //}
15 
16 
17     virtual ~Animal() = 0;
18 };
19 
20 Animal::~Animal()
21 {
22     cout << "Animal 纯虚析构函数调用!" << endl;
23 }
24 
25 //和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。
26 
27 class Cat : public Animal {
28 public:
29     Cat(string name)
30     {
31         cout << "Cat构造函数调用!" << endl;
32         m_Name = new string(name);
33     }
34     virtual void Speak()
35     {
36         cout << *m_Name <<  "小猫在说话!" << endl;
37     }
38     ~Cat()
39     {
40         cout << "Cat析构函数调用!" << endl;
41         if (this->m_Name != NULL) {
42             delete m_Name;
43             m_Name = NULL;
44         }
45     }
46 
47 public:
48     string *m_Name;
49 };
50 
51 void test01()
52 {
53     Animal *animal = new Cat("Tom");
54     animal->Speak();
55 
56     //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
57     //怎么解决?给基类增加一个虚析构函数
58     //虚析构函数就是用来解决通过父类指针释放子类对象
59     delete animal;
60 }
61 
62 int main() {
63 
64     test01();
65 
66     system("pause");
67 
68     return 0;
69 }
复制代码

总结:

​ 1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

​ 2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

​ 3. 拥有纯虚析构函数的类也属于抽象类

 

多态案例三-电脑组装

案例描述:

电脑主要组成部件为 CPU(用于计算),显卡(用于显示),内存条(用于存储)

将每个零件封装出抽象基类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商

创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口

测试时组装三台不同的电脑进行工作

复制代码
 1 #include <iostream>
 2 using namespace std;
 3 class CPU
 4 {
 5 public:
 6     virtual void calculate() = 0;
 7 };
 8 class Videocard
 9 {
10 public:
11     virtual void display() = 0;
12 };
13 class Memory
14 {
15 public:
16     virtual void storage() = 0;
17 };
18 class computer
19 {
20 public:
21     computer(CPU* cpu, Videocard* vc,Memory* mem)
22     {
23         m_cpu = cpu;
24         m_vc = vc;
25         m_mem = mem;
26     }
27     //提供工作的函数
28     void work()
29     {
30         //让零件工作起来,调用接口
31         m_cpu->calculate();
32         m_vc->display();
33         m_mem->storage();
34     }
35     //提供析构函数,来释放三个电脑零件
36     ~computer()
37     {
38         if (m_cpu != 0)
39         {
40             delete m_cpu;
41             m_cpu = 0;
42         }
43         if (m_vc != 0)
44         {
45             delete m_vc;
46             m_vc = 0;
47         }
48         if (m_mem != 0)
49         {
50             delete m_mem;
51             m_mem = 0;
52         }
53 
54     }
55 private:
56     CPU* m_cpu;
57     Videocard* m_vc;
58     Memory* m_mem;
59 };
60 //具体厂商
61 class Intelcpu : public CPU
62 {
63 public:
64     void calculate()
65     {
66         cout << "intel 的cpu 开始工作了" << endl;
67     }
68 };
69 class Intelvc : public Videocard
70 {
71 public:
72     void display()
73     {
74         cout << "intel 的videocard 开始工作了" << endl;
75     }
76 };
77 class Intelmem : public Memory
78 {
79 public:
80     void storage()
81     {
82         cout << "intel 的memory 开始工作了" << endl;
83     }
84 };
85 void test01()
86 {
87     CPU* intelcpu = new  Intelcpu;
88     Videocard* intelvc = new  Intelvc;
89     Memory* intelmem = new Intelmem;
90     computer *computer1=new computer(intelcpu, intelvc, intelmem);
91     computer1->work();
92     delete computer1;
93 }
94 int main()
95 {
96     test01();
97 }
复制代码

 

posted on   在野武将  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示